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