source: abuse/branches/pd/imlib/port/mac/sound.c @ 528

Last change on this file since 528 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 5.1 KB
Line 
1#include "sound.hpp"
2#include "jmalloc.hpp"
3#include "readwav.hpp"
4#include <sound.h>
5#include <stdio.h>
6#include <string.h>
7
8// Maximum number of channels open at one time
9#define MAXCHANNELS     8
10#define USE_ASYNCH
11
12class AsynchChannel {
13public:
14        SndChannelPtr   channel;
15        int playing;
16        SndListHandle sound;
17};
18
19pascal void DonePlaying(SndChannelPtr channel, SndCommand *cmd);
20
21SndCallBackUPP          DonePlayingCB;
22
23class CSoundManager
24{
25public:
26        AsynchChannel   Channel[MAXCHANNELS];
27        int Channels;
28        int Next;
29
30        // Construction & destruction
31        int Init();
32        void Uninit();
33       
34        void PlaySnd(void *, unsigned long size, unsigned int vol);
35       
36        void Silence();
37} SoundMan;
38
39int CSoundManager::Init()
40{
41        OSErr err = noErr;
42
43#ifdef USE_ASYNCH
44        DonePlayingCB = NewSndCallBackProc(DonePlaying);
45#else
46        DonePlayingCB = nil;
47#endif
48
49        Next = 0;
50        Channels = MAXCHANNELS;
51
52        for(short i = 0; i < Channels; i++)
53        {
54                char Data[64];
55                SndListHandle snd;
56                SndListPtr sp;
57
58#if 1
59                // Create resource headers for all channels
60                sp = (SndListPtr)&Data[0];
61                sp->format = 1;
62                sp->numModifiers = 1;
63                sp->modifierPart[0].modNumber = 5;
64                sp->modifierPart[0].modInit = 0x80;
65                sp->numCommands = 1;
66                sp->commandPart[0].cmd = 0x8051;
67                sp->commandPart[0].param1 = 0;
68                sp->commandPart[0].param2 = 0x14;
69               
70                SoundHeaderPtr p = (SoundHeaderPtr)&sp->dataPart[0];
71                p->loopStart = 0;
72                p->loopEnd = 1;
73                p->sampleRate = rate11khz;
74                p->encode = 0;
75                p->baseFrequency = 0x3c;
76
77                PtrToHand((Ptr)sp,(Handle*)&snd,64);
78                HLock((Handle)snd);
79#else
80                snd = (SndListHandle)GetResource('snd ',1001);
81                HLock((Handle)snd);
82#endif
83
84                Channel[i].channel = nil;
85                Channel[i].playing = FALSE;
86                Channel[i].sound = snd;
87
88                // Create all the channels upon creation
89                err = SndNewChannel(&Channel[i].channel,
90                                                        sampledSynth,
91                                                        initMono + initNoInterp,
92                                                        (SndCallBackUPP)DonePlayingCB);
93                                                       
94                if(err != noErr)
95                {
96                        fprintf(stderr,"Aiiiieee! Sound manager couldn't initialize!");
97                        break;
98                }
99        }
100       
101        return (err == noErr);
102}
103
104void CSoundManager::Uninit()
105{       
106        Silence();
107       
108        for(int i = 0; i < Channels; i++)
109        {
110                OSErr err;
111               
112                err = SndDisposeChannel (Channel[i].channel, true);
113               
114                Channel[i].channel = nil;
115                Channel[i].playing = FALSE;
116                DisposeHandle((Handle)Channel[i].sound);
117                Channel[i].sound = nil;
118        }
119}
120
121
122void CSoundManager::PlaySnd(void *data, unsigned long size, unsigned int vol)
123{
124        AsynchChannel * channel = nil;
125        OSErr           err = noErr;
126        SndCommand cmd;
127        short chan;
128       
129        // Find a channel to play from
130#ifdef USE_ASYNCH
131        channel = nil;
132        for(short i = 0; i < Channels; i++)
133        {
134                if(Channel[i].playing == FALSE)
135                {
136                        channel = &Channel[i];
137                        chan = i;
138                        break;
139                }
140        }
141        // If all the channels were busy ignore sound
142        if (channel == nil)
143                return;
144#else
145        channel = &Channel[Next];
146        Next = (Next+1)%Channels;
147#endif
148
149        // grab sound channel           
150        channel->playing = TRUE;
151
152        cmd.cmd = quietCmd;
153        cmd.param1 = 0;
154        cmd.param2 = 0;
155        err = SndDoImmediate(channel->channel, &cmd);
156        cmd.cmd = flushCmd;
157        err = SndDoImmediate(channel->channel, &cmd);
158       
159        SoundHeaderPtr p = (SoundHeaderPtr)&(**channel->sound).dataPart[0];
160        p->samplePtr = (Ptr)data;
161        p->length = size;
162       
163        cmd.cmd = volumeCmd;
164        cmd.param2 = (vol<<17) | (vol<<1);
165        err = SndDoImmediate(channel->channel, &cmd);
166       
167        // play sound on channel
168        err = SndPlay (channel->channel, channel->sound, 1);
169       
170        if (err != noErr)
171        {
172                channel->playing = TRUE;
173                fprintf(stderr,"Couldn't play sound!\n");
174        }
175#ifdef USE_ASYNCH
176        else
177        {
178                // setup callback
179                cmd.cmd = callBackCmd;
180                cmd.param1 = chan;
181                cmd.param2 = (long)channel;
182                err = SndDoCommand (channel->channel, &cmd, 0);
183        }
184#endif
185}
186
187void CSoundManager::Silence()
188{
189        for(short i = 0; i < Channels; i++)
190        {
191                if(Channel[i].playing)
192                {
193                        SndCommand      cmd;
194                        OSErr           err;
195                       
196                        cmd.cmd = quietCmd;
197                        cmd.param1 = 0;
198                        cmd.param2 = 0;
199                        err = SndDoImmediate(Channel[i].channel, &cmd);
200                        cmd.cmd = flushCmd;
201                        err = SndDoImmediate(Channel[i].channel, &cmd);
202                       
203                        // Mark the channel as empty
204                        Channel[i].playing = FALSE;
205                }
206        }
207}
208
209#pragma segment Main
210pascal void DonePlaying(SndChannelPtr channel, SndCommand *cmd)
211{
212#if 0
213        fprintf(stderr,"%x done.\n",(int)cmd->param2);
214#endif
215        ((AsynchChannel *)(cmd->param2))->playing = FALSE;
216}
217
218sound_effect::sound_effect(char *filename)
219{
220        long rate;
221       
222        data = read_wav(filename,rate,size);
223}
224
225
226sound_effect::~sound_effect()
227{
228  if (data)
229        jfree(data);
230}
231
232
233void sound_effect::play(int volume, int pitch, int panpot)
234{
235        SoundMan.PlaySnd(data,size,volume);
236}
237
238int sound_init(int argc, char **argv)
239{
240        return SoundMan.Init();
241}
242
243void sound_uninit()
244{
245  SoundMan.Uninit();
246}
247
248
249song::song(char *filename)
250{
251  data=NULL;
252  Name=strcpy((char *)malloc(strlen(filename)+1),filename);
253  song_id=0;
254}
255
256song::~song()
257{
258  if (playing())
259    stop(); 
260  if (data) free(data);
261  free(Name); 
262
263
264void song::play(unsigned char volume)
265{
266  printf("play song %s, volume %d\n",name(),volume); 
267  song_id=1; 
268}
269
270
271void song::stop(long fadeout_time)                                       // time in ms
272{
273  printf("stop song %s, fade timeout %d\n",name(),fadeout_time);
274  song_id=0;
275 
276}
277
278int song::playing()
279{
280  return song_id; 
281}
282
283void song::set_volume(int volume)                  // 0...127
284{
285}
Note: See TracBrowser for help on using the repository browser.