ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/audio.cpp
Revision: 1.3
Committed: 2000-04-10T18:52:18Z (24 years, 1 month ago) by cebix
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

File Contents

# Content
1 /*
2 * audio.cpp - Audio support
3 *
4 * Basilisk II (C) 1997-2000 Christian Bauer
5 * 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 * Get audio info
52 */
53
54 static int32 AudioGetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
55 {
56 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));
57 M68kRegisters r;
58 int i;
59
60 switch (selector) {
61 case siSampleSize:
62 WriteMacInt16(infoPtr, AudioStatus.sample_size);
63 break;
64
65 case siSampleSizeAvailable: {
66 r.d[0] = audio_num_sample_sizes * 2;
67 Execute68kTrap(0xa122, &r); // NewHandle()
68 uint32 h = r.a[0];
69 if (h == 0)
70 return memFullErr;
71 WriteMacInt16(infoPtr + sil_count, audio_num_sample_sizes);
72 WriteMacInt32(infoPtr + sil_infoHandle, h);
73 uint32 sp = ReadMacInt32(h);
74 for (i=0; i<audio_num_sample_sizes; i++)
75 WriteMacInt16(sp + i*2, audio_sample_sizes[i]);
76 break;
77 }
78
79 case siNumberChannels:
80 WriteMacInt16(infoPtr, AudioStatus.channels);
81 break;
82
83 case siChannelAvailable: {
84 r.d[0] = audio_num_channel_counts * 2;
85 Execute68kTrap(0xa122, &r); // NewHandle()
86 uint32 h = r.a[0];
87 if (h == 0)
88 return memFullErr;
89 WriteMacInt16(infoPtr + sil_count, audio_num_channel_counts);
90 WriteMacInt32(infoPtr + sil_infoHandle, h);
91 uint32 sp = ReadMacInt32(h);
92 for (i=0; i<audio_num_channel_counts; i++)
93 WriteMacInt16(sp + i*2, audio_channel_counts[i]);
94 break;
95 }
96
97 case siSampleRate:
98 WriteMacInt32(infoPtr, AudioStatus.sample_rate);
99 break;
100
101 case siSampleRateAvailable: {
102 r.d[0] = audio_num_sample_rates * 4;
103 Execute68kTrap(0xa122, &r); // NewHandle()
104 uint32 h = r.a[0];
105 if (h == 0)
106 return memFullErr;
107 WriteMacInt16(infoPtr + sil_count, audio_num_sample_rates);
108 WriteMacInt32(infoPtr + sil_infoHandle, h);
109 uint32 lp = ReadMacInt32(h);
110 for (i=0; i<audio_num_sample_rates; i++)
111 WriteMacInt32(lp + i*4, audio_sample_rates[i]);
112 break;
113 }
114
115 case siSpeakerMute:
116 WriteMacInt16(infoPtr, audio_get_speaker_mute());
117 break;
118
119 case siSpeakerVolume:
120 WriteMacInt32(infoPtr, audio_get_speaker_volume());
121 break;
122
123 case siHeadphoneMute:
124 WriteMacInt16(infoPtr, 0);
125 break;
126
127 case siHeadphoneVolume:
128 WriteMacInt32(infoPtr, 0x01000100);
129 break;
130
131 case siHeadphoneVolumeSteps:
132 WriteMacInt16(infoPtr, 13);
133 break;
134
135 case siHardwareMute:
136 WriteMacInt16(infoPtr, audio_get_main_mute());
137 break;
138
139 case siHardwareVolume:
140 WriteMacInt32(infoPtr, audio_get_main_volume());
141 break;
142
143 case siHardwareVolumeSteps:
144 WriteMacInt16(infoPtr, 13);
145 break;
146
147 case siHardwareBusy:
148 WriteMacInt16(infoPtr, AudioStatus.num_sources != 0);
149 break;
150
151 default: // Delegate to Apple Mixer
152 if (AudioStatus.mixer == 0)
153 return badComponentSelector;
154 M68kRegisters r;
155 r.a[0] = infoPtr;
156 r.d[0] = selector;
157 r.a[1] = sourceID;
158 r.a[2] = AudioStatus.mixer;
159 Execute68k(audio_data + adatGetInfo, &r);
160 D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
161 return r.d[0];
162 }
163 return noErr;
164 }
165
166
167 /*
168 * Set audio info
169 */
170
171 static int32 AudioSetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
172 {
173 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));
174 M68kRegisters r;
175 int i;
176
177 switch (selector) {
178 case siSampleSize:
179 D(bug(" set sample size %08lx\n", infoPtr));
180 if (AudioStatus.num_sources)
181 return siDeviceBusyErr;
182 for (i=0; i<audio_num_sample_sizes; i++)
183 if (audio_sample_sizes[i] == infoPtr) {
184 audio_set_sample_size(i);
185 return noErr;
186 }
187 return siInvalidSampleSize;
188
189 case siSampleRate:
190 D(bug(" set sample rate %08lx\n", infoPtr));
191 if (AudioStatus.num_sources)
192 return siDeviceBusyErr;
193 for (i=0; i<audio_num_sample_rates; i++)
194 if (audio_sample_rates[i] == infoPtr) {
195 audio_set_sample_rate(i);
196 return noErr;
197 }
198 return siInvalidSampleRate;
199
200 case siNumberChannels:
201 D(bug(" set number of channels %08lx\n", infoPtr));
202 if (AudioStatus.num_sources)
203 return siDeviceBusyErr;
204 for (i=0; i<audio_num_channel_counts; i++)
205 if (audio_channel_counts[i] == infoPtr) {
206 audio_set_channels(i);
207 return noErr;
208 }
209 return badChannel;
210
211 case siSpeakerMute:
212 audio_set_speaker_mute((uint16)infoPtr);
213 break;
214
215 case siSpeakerVolume:
216 D(bug(" set speaker volume %08lx\n", infoPtr));
217 audio_set_speaker_volume(infoPtr);
218 break;
219
220 case siHeadphoneMute:
221 case siHeadphoneVolume:
222 break;
223
224 case siHardwareMute:
225 audio_set_main_mute((uint16)infoPtr);
226 break;
227
228 case siHardwareVolume:
229 D(bug(" set hardware volume %08lx\n", infoPtr));
230 audio_set_main_volume(infoPtr);
231 break;
232
233 default: // Delegate to Apple Mixer
234 if (AudioStatus.mixer == 0)
235 return badComponentSelector;
236 r.a[0] = infoPtr;
237 r.d[0] = selector;
238 r.a[1] = sourceID;
239 r.a[2] = AudioStatus.mixer;
240 Execute68k(audio_data + adatSetInfo, &r);
241 D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
242 return r.d[0];
243 }
244 return noErr;
245 }
246
247
248 /*
249 * Sound output component dispatch
250 */
251
252 int32 AudioDispatch(uint32 params, uint32 globals)
253 {
254 D(bug("AudioDispatch params %08lx (size %d), what %d\n", params, ReadMacInt8(params + cp_paramSize), (int16)ReadMacInt16(params + cp_what)));
255 M68kRegisters r;
256 uint32 p = params + cp_params;
257
258 switch ((int16)ReadMacInt16(params + cp_what)) {
259 // Basic component functions
260 case kComponentOpenSelect:
261 if (audio_data == 0) {
262
263 // Allocate global data area
264 r.d[0] = SIZEOF_adat;
265 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
266 if (r.a[0] == 0)
267 return memFullErr;
268 audio_data = r.a[0];
269 D(bug(" global data at %08lx\n", audio_data));
270
271 // Put in 68k routines
272 int p = audio_data + adatDelegateCall;
273 WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
274 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
275 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
276 WriteMacInt16(p, 0x7024); p += 2; // moveq #$24,d0
277 WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
278 WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
279 WriteMacInt16(p, M68K_RTS); p += 2; // rts
280 if (p - audio_data != adatOpenMixer)
281 goto adat_error;
282 WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
283 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
284 WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
285 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
286 WriteMacInt16(p, 0x203c); p += 2; // move.l #$06140018,d0
287 WriteMacInt32(p, 0x06140018); p+= 4;
288 WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
289 WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
290 WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
291 WriteMacInt16(p, M68K_RTS); p += 2; // rts
292 if (p - audio_data != adatCloseMixer)
293 goto adat_error;
294 WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
295 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
296 WriteMacInt16(p, 0x203c); p += 2; // move.l #$02180018,d0
297 WriteMacInt32(p, 0x02180018); 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 != adatGetInfo)
303 goto adat_error;
304 WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
305 WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
306 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
307 WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
308 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
309 WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0103,-(sp)
310 WriteMacInt32(p, 0x000c0103); p+= 4;
311 WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
312 WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
313 WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
314 WriteMacInt16(p, M68K_RTS); p += 2; // rts
315 if (p - audio_data != adatSetInfo)
316 goto adat_error;
317 WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
318 WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
319 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
320 WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
321 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
322 WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0104,-(sp)
323 WriteMacInt32(p, 0x000c0104); p+= 4;
324 WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
325 WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
326 WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
327 WriteMacInt16(p, M68K_RTS); p += 2; // rts
328 if (p - audio_data != adatPlaySourceBuffer)
329 goto adat_error;
330 WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
331 WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
332 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
333 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
334 WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
335 WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0108,-(sp)
336 WriteMacInt32(p, 0x000c0108); p+= 4;
337 WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
338 WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
339 WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
340 WriteMacInt16(p, M68K_RTS); p += 2; // rts
341 if (p - audio_data != adatGetSourceData)
342 goto adat_error;
343 WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
344 WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
345 WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
346 WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$00040004,-(sp)
347 WriteMacInt32(p, 0x00040004); p+= 4;
348 WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
349 WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
350 WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
351 WriteMacInt16(p, M68K_RTS); p += 2; // rts
352 if (p - audio_data != adatData)
353 goto adat_error;
354 }
355 AudioAvailable = true;
356 if (open_count == 0)
357 audio_enter_stream();
358 open_count++;
359 return noErr;
360
361 adat_error: printf("FATAL: audio component data block initialization error\n");
362 QuitEmulator();
363 return openErr;
364
365 case kComponentCanDoSelect:
366 case kComponentRegisterSelect:
367 return noErr;
368
369 case kComponentVersionSelect:
370 return 0x00010003;
371
372 case kComponentCloseSelect:
373 open_count--;
374 if (open_count == 0) {
375 if (AudioStatus.mixer) {
376 // Close Apple Mixer
377 r.a[0] = AudioStatus.mixer;
378 Execute68k(audio_data + adatCloseMixer, &r);
379 AudioStatus.mixer = 0;
380 return r.d[0];
381 }
382 AudioStatus.num_sources = 0;
383 audio_exit_stream();
384 }
385 return noErr;
386
387 // Sound component functions
388 case kSoundComponentInitOutputDeviceSelect:
389 D(bug(" InitOutputDevice\n"));
390 if (!audio_open)
391 return noHardwareErr;
392 if (AudioStatus.mixer)
393 return noErr;
394
395 // Init sound component data
396 WriteMacInt32(audio_data + adatData + scd_flags, 0);
397 WriteMacInt32(audio_data + adatData + scd_format, AudioStatus.sample_size == 16 ? 'twos' : 'raw ');
398 WriteMacInt16(audio_data + adatData + scd_numChannels, AudioStatus.channels);
399 WriteMacInt16(audio_data + adatData + scd_sampleSize, AudioStatus.sample_size);
400 WriteMacInt32(audio_data + adatData + scd_sampleRate, AudioStatus.sample_rate);
401 WriteMacInt32(audio_data + adatData + scd_sampleCount, audio_frames_per_block);
402 WriteMacInt32(audio_data + adatData + scd_buffer, 0);
403 WriteMacInt32(audio_data + adatData + scd_reserved, 0);
404 WriteMacInt32(audio_data + adatStreamInfo, 0);
405
406 // Open Apple Mixer
407 r.a[0] = audio_data + adatMixer;
408 r.d[0] = 0;
409 r.a[1] = audio_data + adatData;
410 Execute68k(audio_data + adatOpenMixer, &r);
411 AudioStatus.mixer = ReadMacInt32(audio_data + adatMixer);
412 D(bug(" OpenMixer() returns %08lx, mixer %08lx\n", r.d[0], AudioStatus.mixer));
413 return r.d[0];
414
415 case kSoundComponentAddSourceSelect:
416 D(bug(" AddSource\n"));
417 AudioStatus.num_sources++;
418 goto delegate;
419
420 case kSoundComponentRemoveSourceSelect:
421 D(bug(" RemoveSource\n"));
422 AudioStatus.num_sources--;
423 goto delegate;
424
425 case kSoundComponentStopSourceSelect:
426 D(bug(" StopSource\n"));
427 goto delegate;
428
429 case kSoundComponentPauseSourceSelect:
430 D(bug(" PauseSource\n"));
431 delegate: // Delegate call to Apple Mixer
432 D(bug(" delegating call to Apple Mixer\n"));
433 r.a[0] = AudioStatus.mixer;
434 r.a[1] = params;
435 Execute68k(audio_data + adatDelegateCall, &r);
436 D(bug(" returns %08lx\n", r.d[0]));
437 return r.d[0];
438
439 case kSoundComponentStartSourceSelect:
440 D(bug(" StartSource\n"));
441 return noErr;
442
443 case kSoundComponentGetInfoSelect:
444 return AudioGetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
445
446 case kSoundComponentSetInfoSelect:
447 return AudioSetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
448
449 case kSoundComponentPlaySourceBufferSelect:
450 D(bug(" PlaySourceBuffer\n"));
451 r.d[0] = ReadMacInt32(p);
452 r.a[0] = ReadMacInt32(p + 4);
453 r.a[1] = ReadMacInt32(p + 8);
454 r.a[2] = AudioStatus.mixer;
455 Execute68k(audio_data + adatPlaySourceBuffer, &r);
456 D(bug(" returns %08lx\n", r.d[0]));
457 return r.d[0];
458
459 default:
460 return badComponentSelector;
461 }
462 }