Edinburgh Speech Tools 2.4-release
macosxaudio.cc
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#if defined (SUPPORT_MACOSX_AUDIO)
49
50#include <CoreServices/CoreServices.h>
51#include <stdio.h>
52#include <unistd.h>
53#include <CoreAudio/CoreAudio.h>
54#include <AudioUnit/AudioUnit.h>
55
56int macosx_supported = TRUE;
57
58AudioUnit outau;
59EST_SMatrix *waveMatrix;
60UInt32 waveSize;
61UInt32 waveIndex;
62bool done;
63
64OSStatus render_callback(void *inref,
65 AudioUnitRenderActionFlags *inflags,
66 const AudioTimeStamp *instamp,
67 UInt32 inbus,
68 UInt32 inframes,
69 AudioBufferList *ioData)
70{
71
72 // fill each channel with available audio data
73
74 UInt32 channels = ioData->mNumberBuffers;
75 int totalNumberOfBytes = waveSize;
76 int channelBytesLeft = totalNumberOfBytes - waveIndex;
77 int bufferSize = ioData->mBuffers[0].mDataByteSize;
78
79 if(channelBytesLeft > 0) {
80 if(channelBytesLeft < bufferSize) {
81 for(UInt32 i = 0; i < channels; ++i) {
82 waveMatrix->copy_column((int)i, (int short*)ioData->mBuffers[i].mData, waveIndex/2, channelBytesLeft/2);
83 memset((char*)ioData->mBuffers[i].mData + channelBytesLeft, 0, bufferSize - channelBytesLeft) ;
84 }
85 waveIndex += channelBytesLeft;
86 } else {
87 for(UInt32 i = 0; i < channels; ++i)
88 waveMatrix->copy_column((int)i, (int short*)ioData->mBuffers[i].mData, waveIndex/2, bufferSize/2);
89 waveIndex += bufferSize;
90 }
91 } else {
92 for(UInt32 i = 0; i < channels; ++i)
93 memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
94 done = TRUE;
95 }
96
97 return noErr;
98}
99
100
101void CreateDefaultAU()
102{
103 OSStatus err = noErr;
104
105 // Open the default output unit
106 ComponentDescription desc;
107 desc.componentType = kAudioUnitType_Output;
108 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
109 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
110 desc.componentFlags = 0;
111 desc.componentFlagsMask = 0;
112
113 Component comp = FindNextComponent(NULL, &desc);
114 if (comp == NULL) { printf ("FindNextComponent\n"); return; }
115
116 err = OpenAComponent(comp, &outau);
117 if (comp == NULL) { printf ("OpenAComponent=%ld\n", long(err)); return; }
118
119 // Set up render callback
120 AURenderCallbackStruct input;
121 input.inputProc = render_callback;
122 input.inputProcRefCon = NULL;
123
124 err = AudioUnitSetProperty (outau,
125 kAudioUnitProperty_SetRenderCallback,
126 kAudioUnitScope_Input,
127 0,
128 &input,
129 sizeof(input));
130 if (err) { printf ("AudioUnitSetProperty-CB=%ld\n", long(err)); return; }
131
132}
133
134int play_macosx_wave(EST_Wave &inwave, EST_Option &al)
135{
136 OSStatus err;
137 AudioStreamBasicDescription waveformat, outformat;
138 UInt32 size = sizeof(AudioStreamBasicDescription);
139 UInt32 running;
140
141 CreateDefaultAU();
142
143 // The EST_Wave structure will allow us to access individula channels
144 // so this is set up using kAudioFormatFlagIsNonInterleaved format.
145 // Here the per packet and per frame info is per channel.
146 waveformat.mSampleRate = (Float64)inwave.sample_rate();
147 waveformat.mFormatID = kAudioFormatLinearPCM;
148 waveformat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
149 | kAudioFormatFlagsNativeEndian
150 | kLinearPCMFormatFlagIsPacked
151 | kAudioFormatFlagIsNonInterleaved;
152 waveformat.mFramesPerPacket = 1;
153 waveformat.mChannelsPerFrame = inwave.num_channels();
154 waveformat.mBytesPerPacket = 2;
155 waveformat.mBytesPerFrame = 2;
156 waveformat.mBitsPerChannel = 16;
157
158 err = AudioUnitSetProperty(outau,
159 kAudioUnitProperty_StreamFormat,
160 kAudioUnitScope_Input,
161 0,
162 &waveformat,
163 size);
164 if (err != noErr) {
165 cerr << "Error setting input audio stream format." << endl;
166 CloseComponent(outau);
167 return -1;
168 }
169
170 err = AudioUnitGetProperty(outau,
171 kAudioUnitProperty_StreamFormat,
172 kAudioUnitScope_Output,
173 0,
174 &outformat,
175 &size);
176 if (err != noErr) {
177 cerr << "Error getting output audio stream format." << endl;
178 CloseComponent(outau);
179 return -1;
180 }
181
182 err = AudioUnitInitialize(outau);
183 if (err) {
184 printf ("AudioUnitInitialize=%ld\n", long(err));
185 return -1;
186 }
187
188 // set up for playing
189 waveSize = inwave.num_samples()*sizeof(short);
190 waveMatrix = &inwave.values();
191 done = FALSE;
192 waveIndex = 0;
193
194 err = AudioOutputUnitStart(outau);
195 if (err != noErr) {
196 cerr << "Error starting audio outup: " << err << endl;
197 CloseComponent(outau);
198 return -1;
199 }
200
201 // Poll every 50ms whether the sound has stopped playing yet.
202 // Probably not the best way of doing things.
203 size = sizeof(UInt32);
204 do {
205 usleep(50 * 1000);
206 err = AudioUnitGetProperty(outau, kAudioOutputUnitProperty_IsRunning,
207 kAudioUnitScope_Global, 0, &running, &size);
208 } while (err == noErr && running && !done);
209
210 CloseComponent (outau);
211
212 return 1;
213}
214
215#else
216
217int macosx_supported = FALSE;
218
219int play_macosx_wave(EST_Wave &inwave, EST_Option &al)
220{
221 (void)inwave;
222 (void)al;
223 cerr << "OS X Core Audio in not supported in this configuration." << endl;
224 return -1;
225}
226
227#endif
void copy_column(int c, T *buf, int offset=0, int num=-1) const
Definition: EST_TMatrix.cc:420
int num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
int num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143