Edinburgh Speech Tools  2.1-release
macosxaudio.cc
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1996-2009 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Brian Foley */
34 /* bfoley@compsoc.nuigalway.ie */
35 /* Date : February 2004 */
36 /*************************************************************************/
37 /* OSX 10.6 updates */
38 /* Author : Rob Clark */
39 /* robert@cstr.ed.ac.uk */
40 /* Date : Jan 2009 */
41 /*=======================================================================*/
42 #include "EST_unix.h"
43 #include "EST_cutils.h"
44 #include "EST_Wave.h"
45 #include "EST_Option.h"
46 #include "audioP.h"
47 
48 using namespace std;
49 
50 
51 #if defined (SUPPORT_MACOSX_AUDIO)
52 
53 #include <CoreServices/CoreServices.h>
54 #include <stdio.h>
55 #include <unistd.h>
56 #include <CoreAudio/CoreAudio.h>
57 #include <AudioUnit/AudioUnit.h>
58 
60 
61 AudioUnit outau;
62 EST_SMatrix *waveMatrix;
63 UInt32 waveSize;
64 UInt32 waveIndex;
65 bool done;
66 
67 OSStatus render_callback(void *inref,
68  AudioUnitRenderActionFlags *inflags,
69  const AudioTimeStamp *instamp,
70  UInt32 inbus,
71  UInt32 inframes,
72  AudioBufferList *ioData)
73 {
74 
75  // fill each channel with available audio data
76 
77  UInt32 channels = ioData->mNumberBuffers;
78  int totalNumberOfBytes = waveSize;
79  int channelBytesLeft = totalNumberOfBytes - waveIndex;
80  int bufferSize = ioData->mBuffers[0].mDataByteSize;
81 
82  if(channelBytesLeft > 0) {
83  if(channelBytesLeft < bufferSize) {
84  for(UInt32 i = 0; i < channels; ++i) {
85  waveMatrix->copy_column((int)i, (int short*)ioData->mBuffers[i].mData, waveIndex/2, channelBytesLeft/2);
86  memset((char*)ioData->mBuffers[i].mData + channelBytesLeft, 0, bufferSize - channelBytesLeft) ;
87  }
88  waveIndex += channelBytesLeft;
89  } else {
90  for(UInt32 i = 0; i < channels; ++i)
91  waveMatrix->copy_column((int)i, (int short*)ioData->mBuffers[i].mData, waveIndex/2, bufferSize/2);
92  waveIndex += bufferSize;
93  }
94  } else {
95  for(UInt32 i = 0; i < channels; ++i)
96  memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
97  done = TRUE;
98  }
99 
100  return noErr;
101 }
102 
103 
104 void CreateDefaultAU()
105 {
106  OSStatus err = noErr;
107 
108  // Open the default output unit
109  ComponentDescription desc;
110  desc.componentType = kAudioUnitType_Output;
111  desc.componentSubType = kAudioUnitSubType_DefaultOutput;
112  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
113  desc.componentFlags = 0;
114  desc.componentFlagsMask = 0;
115 
116  Component comp = FindNextComponent(NULL, &desc);
117  if (comp == NULL) { printf ("FindNextComponent\n"); return; }
118 
119  err = OpenAComponent(comp, &outau);
120  if (comp == NULL) { printf ("OpenAComponent=%ld\n", long(err)); return; }
121 
122  // Set up render callback
123  AURenderCallbackStruct input;
124  input.inputProc = render_callback;
125  input.inputProcRefCon = NULL;
126 
127  err = AudioUnitSetProperty (outau,
128  kAudioUnitProperty_SetRenderCallback,
129  kAudioUnitScope_Input,
130  0,
131  &input,
132  sizeof(input));
133  if (err) { printf ("AudioUnitSetProperty-CB=%ld\n", long(err)); return; }
134 
135 }
136 
137 int play_macosx_wave(EST_Wave &inwave, EST_Option &al)
138 {
139  OSStatus err;
140  AudioStreamBasicDescription waveformat, outformat;
141  UInt32 size = sizeof(AudioStreamBasicDescription);
142  UInt32 running;
143 
144  CreateDefaultAU();
145 
146  // The EST_Wave structure will allow us to access individula channels
147  // so this is set up using kAudioFormatFlagIsNonInterleaved format.
148  // Here the per packet and per frame info is per channel.
149  waveformat.mSampleRate = (Float64)inwave.sample_rate();
150  waveformat.mFormatID = kAudioFormatLinearPCM;
151  waveformat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
152  | kAudioFormatFlagsNativeEndian
153  | kLinearPCMFormatFlagIsPacked
154  | kAudioFormatFlagIsNonInterleaved;
155  waveformat.mFramesPerPacket = 1;
156  waveformat.mChannelsPerFrame = inwave.num_channels();
157  waveformat.mBytesPerPacket = 2;
158  waveformat.mBytesPerFrame = 2;
159  waveformat.mBitsPerChannel = 16;
160 
161  err = AudioUnitSetProperty(outau,
162  kAudioUnitProperty_StreamFormat,
163  kAudioUnitScope_Input,
164  0,
165  &waveformat,
166  size);
167  if (err != noErr) {
168  cerr << "Error setting input audio stream format." << endl;
169  CloseComponent(outau);
170  return -1;
171  }
172 
173  err = AudioUnitGetProperty(outau,
174  kAudioUnitProperty_StreamFormat,
175  kAudioUnitScope_Output,
176  0,
177  &outformat,
178  &size);
179  if (err != noErr) {
180  cerr << "Error getting output audio stream format." << endl;
181  CloseComponent(outau);
182  return -1;
183  }
184 
185  err = AudioUnitInitialize(outau);
186  if (err) {
187  printf ("AudioUnitInitialize=%ld\n", long(err));
188  return -1;
189  }
190 
191  // set up for playing
192  waveSize = inwave.num_samples()*sizeof(short);
193  waveMatrix = &inwave.values();
194  done = FALSE;
195  waveIndex = 0;
196 
197  err = AudioOutputUnitStart(outau);
198  if (err != noErr) {
199  cerr << "Error starting audio outup: " << err << endl;
200  CloseComponent(outau);
201  return -1;
202  }
203 
204  // Poll every 50ms whether the sound has stopped playing yet.
205  // Probably not the best way of doing things.
206  size = sizeof(UInt32);
207  do {
208  usleep(50 * 1000);
209  err = AudioUnitGetProperty(outau, kAudioOutputUnitProperty_IsRunning,
210  kAudioUnitScope_Global, 0, &running, &size);
211  } while (err == noErr && running && !done);
212 
213  CloseComponent (outau);
214 
215  return 1;
216 }
217 
218 #else
219 
221 
223 {
224  (void)inwave;
225  (void)al;
226  cerr << "OS X Core Audio in not supported in this configuration." << endl;
227  return -1;
228 }
229 
230 #endif
A class for storing digital waveforms. The waveform is stored as an array of 16 bit shorts...
Definition: EST_Wave.h:64
void copy_column(ssize_t c, T *buf, ptrdiff_t offset=0, int num=-1) const
Definition: EST_TMatrix.cc:420
ssize_t num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143
int macosx_supported
Definition: macosxaudio.cc:220
void err(const char *message, LISP x) EST_NORETURN
Definition: slib.cc:608
const EST_SMatrix & values() const
Definition: EST_Wave.h:177
#define FALSE
Definition: EST_bool.h:119
NULL
Definition: EST_WFST.cc:55
int play_macosx_wave(EST_Wave &inwave, EST_Option &al)
Definition: macosxaudio.cc:222
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
ssize_t num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
#define TRUE
Definition: EST_bool.h:118