1 /*
2 * Copyright (C) 2004-2005 Vadim Berezniker
3 * http://www.kryptolus.com
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "stdafx.h"
23
24
25
26 #include <CoreServices/CoreServices.h>
27 #include <AudioUnit/AudioUnit.h>
28 #include <AudioToolbox/AudioToolbox.h>
29
30
31
32 #include "kry_marker.h"
33 #include "sound.h"
34 #include "sound_out.h"
35 #include "gui_main_audio.h"
36
37
38
39 void soundserver_fill(struct sound_play_data *data);
40 void mySoundProc(void *pSoundBuffer,long bufferLen);
41 void soundserver_close(void);
42
43
44
45 static USER_CALLBACK m_pUserCallback = NULL;
46 static gboolean m_soundserver_mute[2];
47 static AudioUnit soundOutU;
48 static int bufsize = 512;
49 static unsigned char *buffer;
50 static unsigned char playbackIsFinished = 0;
51 static signed char closed = -1;
52
53
54
myAURenderCallback(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)55 static OSStatus myAURenderCallback (void *inRefCon,
56 AudioUnitRenderActionFlags * ioActionFlags,
57 const AudioTimeStamp * inTimeStamp,
58 UInt32 inBusNumber,
59 UInt32 inNumberFrames, AudioBufferList * ioData)
60
61 {
62 struct sound_play_data *info = (struct sound_play_data*)inRefCon;
63 int packetsize = info->sfinfo->channels*2;
64
65 if (playbackIsFinished)
66 return noErr;
67
68 ioData->mBuffers[0].mNumberChannels = info->sfinfo->channels;
69
70 if (packetsize * inNumberFrames > bufsize) {
71 buffer = (unsigned char*)realloc (buffer, packetsize * inNumberFrames);
72 bufsize = packetsize * inNumberFrames;
73 }
74
75 int rdsize = m_pUserCallback(buffer,inNumberFrames*packetsize,info);
76
77 /* XXX muting isn't done (although who cares about it?)*/
78
79 if (rdsize == 0) goto alldone;
80
81 ioData->mBuffers[0].mData = buffer;
82
83 ioData->mBuffers[0].mDataByteSize = rdsize;
84
85 return noErr;
86
87 alldone: ;
88
89 gui_main_audio_play_mode(SOUND_NOT_PLAYING);
90 playbackIsFinished = 1;
91
92 ioData->mBuffers[0].mDataByteSize = 0;
93
94 AudioOutputUnitStop(soundOutU);
95
96 return noErr;
97
98 }
99
100
101
soundserver_open(USER_CALLBACK pUserCallback,int channels,int samplerate)102 int soundserver_open(USER_CALLBACK pUserCallback, int channels, int samplerate)
103 {
104 playbackIsFinished = 0;
105
106 if (closed == 0) soundserver_close();
107
108 closed = 0;
109
110 int stereo = (channels == 2);
111
112 AudioStreamBasicDescription inFormat;
113
114 size_t s = sizeof (inFormat);
115
116 inFormat = (AudioStreamBasicDescription)
117 {
118 samplerate, kAudioFormatLinearPCM,
119
120 kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian
121
122 | kLinearPCMFormatFlagIsPacked, stereo ? 4 : 2, 1, stereo ? 4 : 2,
123
124 stereo ? 2 : 1, 16, 0
125 };
126
127 AudioUnitSetProperty (soundOutU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inFormat, s);
128
129 m_pUserCallback = pUserCallback;
130
131 return TRUE;
132 }
133
134
135
soundserver_close(void)136 void soundserver_close(void)
137 {
138 if (closed != 0) return;
139
140 closed = 1;
141 playbackIsFinished = 1;
142
143 AudioOutputUnitStop(soundOutU);
144 }
145
146
147
soundserver_stop()148 void soundserver_stop()
149 {
150 if (closed != 0) return;
151
152 playbackIsFinished = 1;
153
154 AudioOutputUnitStop(soundOutU);
155 }
156
soundserver_init()157 void soundserver_init()
158 {
159 buffer = (unsigned char*) malloc (4096);
160
161 ComponentDescription desc =
162 {
163 kAudioUnitType_Output, kAudioUnitSubType_DefaultOutput, 0, 0, 0
164 };
165
166 Component c = FindNextComponent (NULL, &desc);
167 OpenAComponent (c, &soundOutU);
168 AudioUnitInitialize (soundOutU);
169 }
170
171
172
soundserver_mute(int channel)173 void soundserver_mute(int channel)
174 {
175 m_soundserver_mute[channel] = 1;
176 }
177
178
soundserver_play(struct sound_play_data * data)179 void soundserver_play(struct sound_play_data *data)
180 {
181 if (closed != 0) return;
182
183 AURenderCallbackStruct callbackSetup;
184
185 callbackSetup.inputProc = myAURenderCallback;
186 callbackSetup.inputProcRefCon = data;
187
188 soundserver_stop();
189
190 playbackIsFinished = 0;
191
192 AudioUnitSetProperty (soundOutU, kAudioUnitProperty_SetRenderCallback,
193
194 kAudioUnitScope_Input, 0, &callbackSetup,
195
196 sizeof (callbackSetup));
197
198 AudioOutputUnitStart(soundOutU);
199 }
200
201
202
soundserver_get_position_type()203 enum sound_position_type soundserver_get_position_type()
204 {
205 return POSITION_AUTOMATIC;
206 }
207
soundserver_get_position(int * pos)208 enum soundserver_position_rv soundserver_get_position(int *pos)
209 {
210 return SOUNDSERVER_ERROR;
211 }
212
213
214