source: abuse/tags/pd/macabuse/imlib/port/mac/sound.c @ 49

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