ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/audio.cpp
Revision: 1.5
Committed: 2000-07-22T16:07:14Z (24 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.4: +1 -1 lines
Log Message:
- new FOURCC() macro in macos_util.h

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * audio.cpp - Audio support
3     *
4 cebix 1.3 * Basilisk II (C) 1997-2000 Christian Bauer
5 cebix 1.1 * Portions (C) 1997-1999 Marc Hellwig
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*
23     * SEE ALSO
24     * Inside Macintosh: Sound, chapter 5 "Sound Components"
25     */
26    
27     #include "sysdeps.h"
28     #include "cpu_emulation.h"
29     #include "macos_util.h"
30     #include "emul_op.h"
31     #include "main.h"
32     #include "audio.h"
33     #include "audio_defs.h"
34    
35     #define DEBUG 0
36     #include "debug.h"
37    
38    
39     // Global variables
40     struct audio_status AudioStatus; // Current audio status (sample rate etc.)
41     bool audio_open = false; // Flag: audio is initialized and ready
42     int audio_frames_per_block; // Number of audio frames per block
43     uint32 audio_component_flags; // Component feature flags
44     uint32 audio_data = 0; // Mac address of global data area
45     static int open_count = 0; // Open/close nesting count
46    
47     bool AudioAvailable = false; // Flag: audio output available (from the software point of view)
48    
49    
50     /*
51 cebix 1.4 * Reset audio emulation
52     */
53    
54     void AudioReset(void)
55     {
56     audio_data = 0;
57     }
58    
59    
60     /*
61 cebix 1.1 * Get audio info
62     */
63    
64     static int32 AudioGetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
65     {
66     D(bug(" AudioGetInfo %c%c%c%c, infoPtr %08lx, source ID %08lx\n", selector >> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID));
67     M68kRegisters r;
68     int i;
69    
70     switch (selector) {
71     case siSampleSize:
72     WriteMacInt16(infoPtr, AudioStatus.sample_size);
73     break;
74    
75     case siSampleSizeAvailable: {
76     r.d[0] = audio_num_sample_sizes * 2;
77     Execute68kTrap(0xa122, &r); // NewHandle()
78     uint32 h = r.a[0];
79     if (h == 0)
80     return memFullErr;
81     WriteMacInt16(infoPtr + sil_count, audio_num_sample_sizes);
82     WriteMacInt32(infoPtr + sil_infoHandle, h);
83     uint32 sp = ReadMacInt32(h);
84     for (i=0; i<audio_num_sample_sizes; i++)
85     WriteMacInt16(sp + i*2, audio_sample_sizes[i]);
86     break;
87     }
88    
89     case siNumberChannels:
90     WriteMacInt16(infoPtr, AudioStatus.channels);
91     break;
92    
93     case siChannelAvailable: {
94     r.d[0] = audio_num_channel_counts * 2;
95     Execute68kTrap(0xa122, &r); // NewHandle()
96     uint32 h = r.a[0];
97     if (h == 0)
98     return memFullErr;
99     WriteMacInt16(infoPtr + sil_count, audio_num_channel_counts);
100     WriteMacInt32(infoPtr + sil_infoHandle, h);
101     uint32 sp = ReadMacInt32(h);
102     for (i=0; i<audio_num_channel_counts; i++)
103     WriteMacInt16(sp + i*2, audio_channel_counts[i]);
104     break;
105     }
106    
107     case siSampleRate:
108     WriteMacInt32(infoPtr, AudioStatus.sample_rate);
109     break;
110    
111     case siSampleRateAvailable: {
112     r.d[0] = audio_num_sample_rates * 4;
113     Execute68kTrap(0xa122, &r); // NewHandle()
114     uint32 h = r.a[0];
115     if (h == 0)
116     return memFullErr;
117     WriteMacInt16(infoPtr + sil_count, audio_num_sample_rates);
118     WriteMacInt32(infoPtr + sil_infoHandle, h);
119     uint32 lp = ReadMacInt32(h);
120     for (i=0; i<audio_num_sample_rates; i++)
121     WriteMacInt32(lp + i*4, audio_sample_rates[i]);
122     break;
123     }
124    
125     case siSpeakerMute:
126 cebix 1.2 WriteMacInt16(infoPtr, audio_get_speaker_mute());
127 cebix 1.1 break;
128    
129     case siSpeakerVolume:
130 cebix 1.2 WriteMacInt32(infoPtr, audio_get_speaker_volume());
131     break;
132    
133     case siHeadphoneMute:
134     WriteMacInt16(infoPtr, 0);
135     break;
136    
137     case siHeadphoneVolume:
138     WriteMacInt32(infoPtr, 0x01000100);
139     break;
140    
141     case siHeadphoneVolumeSteps:
142     WriteMacInt16(infoPtr, 13);
143 cebix 1.1 break;
144    
145     case siHardwareMute:
146 cebix 1.2 WriteMacInt16(infoPtr, audio_get_main_mute());
147 cebix 1.1 break;
148    
149     case siHardwareVolume:
150 cebix 1.2 WriteMacInt32(infoPtr, audio_get_main_volume());
151     break;
152    
153     case siHardwareVolumeSteps:
154     WriteMacInt16(infoPtr, 13);
155 cebix 1.1 break;
156    
157     case siHardwareBusy:
158     WriteMacInt16(infoPtr, AudioStatus.num_sources != 0);
159     break;
160    
161     default: // Delegate to Apple Mixer
162     if (AudioStatus.mixer == 0)
163     return badComponentSelector;
164     M68kRegisters r;
165     r.a[0] = infoPtr;
166     r.d[0] = selector;
167     r.a[1] = sourceID;
168     r.a[2] = AudioStatus.mixer;
169     Execute68k(audio_data + adatGetInfo, &r);
170     D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
171     return r.d[0];
172     }
173     return noErr;
174     }
175    
176    
177     /*
178     * Set audio info
179     */
180    
181     static int32 AudioSetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
182     {
183     D(bug(" AudioSetInfo %c%c%c%c, infoPtr %08lx, source ID %08lx\n", selector >> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID));
184     M68kRegisters r;
185     int i;
186    
187     switch (selector) {
188     case siSampleSize:
189     D(bug(" set sample size %08lx\n", infoPtr));
190     if (AudioStatus.num_sources)
191     return siDeviceBusyErr;
192     for (i=0; i<audio_num_sample_sizes; i++)
193     if (audio_sample_sizes[i] == infoPtr) {
194     audio_set_sample_size(i);
195     return noErr;
196     }
197     return siInvalidSampleSize;
198    
199     case siSampleRate:
200     D(bug(" set sample rate %08lx\n", infoPtr));
201     if (AudioStatus.num_sources)
202     return siDeviceBusyErr;
203     for (i=0; i<audio_num_sample_rates; i++)
204     if (audio_sample_rates[i] == infoPtr) {
205     audio_set_sample_rate(i);
206     return noErr;
207     }
208     return siInvalidSampleRate;
209    
210     case siNumberChannels:
211     D(bug(" set number of channels %08lx\n", infoPtr));
212     if (AudioStatus.num_sources)
213     return siDeviceBusyErr;
214     for (i=0; i<audio_num_channel_counts; i++)
215     if (audio_channel_counts[i] == infoPtr) {
216     audio_set_channels(i);
217     return noErr;
218     }
219     return badChannel;
220    
221     case siSpeakerMute:
222 cebix 1.2 audio_set_speaker_mute((uint16)infoPtr);
223 cebix 1.1 break;
224    
225     case siSpeakerVolume:
226     D(bug(" set speaker volume %08lx\n", infoPtr));
227 cebix 1.2 audio_set_speaker_volume(infoPtr);
228     break;
229    
230     case siHeadphoneMute:
231     case siHeadphoneVolume:
232 cebix 1.1 break;
233    
234     case siHardwareMute:
235 cebix 1.2 audio_set_main_mute((uint16)infoPtr);
236 cebix 1.1 break;
237    
238     case siHardwareVolume:
239     D(bug(" set hardware volume %08lx\n", infoPtr));
240 cebix 1.2 audio_set_main_volume(infoPtr);
241 cebix 1.1 break;
242    
243     default: // Delegate to Apple Mixer
244     if (AudioStatus.mixer == 0)
245     return badComponentSelector;
246     r.a[0] = infoPtr;
247     r.d[0] = selector;
248     r.a[1] = sourceID;
249     r.a[2] = AudioStatus.mixer;
250     Execute68k(audio_data + adatSetInfo, &r);
251     D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
252     return r.d[0];
253     }
254     return noErr;
255     }
256    
257    
258     /*
259     * Sound output component dispatch
260     */
261    
262     int32 AudioDispatch(uint32 params, uint32 globals)
263     {
264     D(bug("AudioDispatch params %08lx (size %d), what %d\n", params, ReadMacInt8(params + cp_paramSize), (int16)ReadMacInt16(params + cp_what)));
265     M68kRegisters r;
266     uint32 p = params + cp_params;
267    
268     switch ((int16)ReadMacInt16(params + cp_what)) {
269     // Basic component functions
270     case kComponentOpenSelect:
271     if (audio_data == 0) {
272    
273     // Allocate global data area
274     r.d[0] = SIZEOF_adat;
275     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
276     if (r.a[0] == 0)
277     return memFullErr;
278     audio_data = r.a[0];
279     D(bug(" global data at %08lx\n", audio_data));
280    
281     // Put in 68k routines
282     int p = audio_data + adatDelegateCall;
283     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
284     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
285     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
286     WriteMacInt16(p, 0x7024); p += 2; // moveq #$24,d0
287     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
288     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
289     WriteMacInt16(p, M68K_RTS); p += 2; // rts
290     if (p - audio_data != adatOpenMixer)
291     goto adat_error;
292     WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
293     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
294     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
295     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
296     WriteMacInt16(p, 0x203c); p += 2; // move.l #$06140018,d0
297     WriteMacInt32(p, 0x06140018); p+= 4;
298     WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
299     WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
300     WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
301     WriteMacInt16(p, M68K_RTS); p += 2; // rts
302     if (p - audio_data != adatCloseMixer)
303     goto adat_error;
304     WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
305     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
306     WriteMacInt16(p, 0x203c); p += 2; // move.l #$02180018,d0
307     WriteMacInt32(p, 0x02180018); p+= 4;
308     WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
309     WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
310     WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
311     WriteMacInt16(p, M68K_RTS); p += 2; // rts
312     if (p - audio_data != adatGetInfo)
313     goto adat_error;
314     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
315     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
316     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
317     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
318     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
319     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0103,-(sp)
320     WriteMacInt32(p, 0x000c0103); p+= 4;
321     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
322     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
323     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
324     WriteMacInt16(p, M68K_RTS); p += 2; // rts
325     if (p - audio_data != adatSetInfo)
326     goto adat_error;
327     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
328     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
329     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
330     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
331     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
332     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0104,-(sp)
333     WriteMacInt32(p, 0x000c0104); p+= 4;
334     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
335     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
336     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
337     WriteMacInt16(p, M68K_RTS); p += 2; // rts
338     if (p - audio_data != adatPlaySourceBuffer)
339     goto adat_error;
340     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
341     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
342     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
343     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
344     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
345     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0108,-(sp)
346     WriteMacInt32(p, 0x000c0108); p+= 4;
347     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
348     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
349     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
350     WriteMacInt16(p, M68K_RTS); p += 2; // rts
351     if (p - audio_data != adatGetSourceData)
352     goto adat_error;
353     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
354     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
355     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
356     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$00040004,-(sp)
357     WriteMacInt32(p, 0x00040004); p+= 4;
358     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
359     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
360     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
361     WriteMacInt16(p, M68K_RTS); p += 2; // rts
362     if (p - audio_data != adatData)
363     goto adat_error;
364     }
365     AudioAvailable = true;
366     if (open_count == 0)
367     audio_enter_stream();
368     open_count++;
369     return noErr;
370    
371     adat_error: printf("FATAL: audio component data block initialization error\n");
372     QuitEmulator();
373     return openErr;
374    
375     case kComponentCanDoSelect:
376     case kComponentRegisterSelect:
377     return noErr;
378    
379     case kComponentVersionSelect:
380 cebix 1.2 return 0x00010003;
381 cebix 1.1
382     case kComponentCloseSelect:
383     open_count--;
384     if (open_count == 0) {
385     if (AudioStatus.mixer) {
386     // Close Apple Mixer
387     r.a[0] = AudioStatus.mixer;
388     Execute68k(audio_data + adatCloseMixer, &r);
389     AudioStatus.mixer = 0;
390     return r.d[0];
391     }
392     AudioStatus.num_sources = 0;
393     audio_exit_stream();
394     }
395     return noErr;
396    
397     // Sound component functions
398     case kSoundComponentInitOutputDeviceSelect:
399     D(bug(" InitOutputDevice\n"));
400     if (!audio_open)
401     return noHardwareErr;
402     if (AudioStatus.mixer)
403     return noErr;
404    
405     // Init sound component data
406     WriteMacInt32(audio_data + adatData + scd_flags, 0);
407 cebix 1.5 WriteMacInt32(audio_data + adatData + scd_format, AudioStatus.sample_size == 16 ? FOURCC('t','w','o','s') : FOURCC('r','a','w',' '));
408 cebix 1.1 WriteMacInt16(audio_data + adatData + scd_numChannels, AudioStatus.channels);
409     WriteMacInt16(audio_data + adatData + scd_sampleSize, AudioStatus.sample_size);
410     WriteMacInt32(audio_data + adatData + scd_sampleRate, AudioStatus.sample_rate);
411     WriteMacInt32(audio_data + adatData + scd_sampleCount, audio_frames_per_block);
412     WriteMacInt32(audio_data + adatData + scd_buffer, 0);
413     WriteMacInt32(audio_data + adatData + scd_reserved, 0);
414     WriteMacInt32(audio_data + adatStreamInfo, 0);
415    
416     // Open Apple Mixer
417     r.a[0] = audio_data + adatMixer;
418     r.d[0] = 0;
419     r.a[1] = audio_data + adatData;
420     Execute68k(audio_data + adatOpenMixer, &r);
421     AudioStatus.mixer = ReadMacInt32(audio_data + adatMixer);
422     D(bug(" OpenMixer() returns %08lx, mixer %08lx\n", r.d[0], AudioStatus.mixer));
423     return r.d[0];
424    
425     case kSoundComponentAddSourceSelect:
426     D(bug(" AddSource\n"));
427     AudioStatus.num_sources++;
428     goto delegate;
429    
430     case kSoundComponentRemoveSourceSelect:
431     D(bug(" RemoveSource\n"));
432     AudioStatus.num_sources--;
433     goto delegate;
434    
435     case kSoundComponentStopSourceSelect:
436     D(bug(" StopSource\n"));
437     goto delegate;
438    
439     case kSoundComponentPauseSourceSelect:
440     D(bug(" PauseSource\n"));
441     delegate: // Delegate call to Apple Mixer
442     D(bug(" delegating call to Apple Mixer\n"));
443     r.a[0] = AudioStatus.mixer;
444     r.a[1] = params;
445     Execute68k(audio_data + adatDelegateCall, &r);
446     D(bug(" returns %08lx\n", r.d[0]));
447     return r.d[0];
448    
449     case kSoundComponentStartSourceSelect:
450     D(bug(" StartSource\n"));
451     return noErr;
452    
453     case kSoundComponentGetInfoSelect:
454     return AudioGetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
455    
456     case kSoundComponentSetInfoSelect:
457     return AudioSetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
458    
459     case kSoundComponentPlaySourceBufferSelect:
460     D(bug(" PlaySourceBuffer\n"));
461     r.d[0] = ReadMacInt32(p);
462     r.a[0] = ReadMacInt32(p + 4);
463     r.a[1] = ReadMacInt32(p + 8);
464     r.a[2] = AudioStatus.mixer;
465     Execute68k(audio_data + adatPlaySourceBuffer, &r);
466     D(bug(" returns %08lx\n", r.d[0]));
467     return r.d[0];
468    
469     default:
470     return badComponentSelector;
471     }
472     }