ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/audio.cpp
Revision: 1.7
Committed: 2001-02-02T20:52:56Z (23 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-17022001, snapshot-29052001, release-0_9-1
Changes since 1.6: +1 -1 lines
Log Message:
- bumped version number to 0.9
- updated copyright dates

File Contents

# Content
1 /*
2 * audio.cpp - Audio support
3 *
4 * Basilisk II (C) 1997-2001 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 * Reset audio emulation
52 */
53
54 void AudioReset(void)
55 {
56 audio_data = 0;
57 }
58
59
60 /*
61 * 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 WriteMacInt16(infoPtr, audio_get_speaker_mute());
127 break;
128
129 case siSpeakerVolume:
130 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 break;
144
145 case siHardwareMute:
146 WriteMacInt16(infoPtr, audio_get_main_mute());
147 break;
148
149 case siHardwareVolume:
150 WriteMacInt32(infoPtr, audio_get_main_volume());
151 break;
152
153 case siHardwareVolumeSteps:
154 WriteMacInt16(infoPtr, 13);
155 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 audio_set_speaker_mute((uint16)infoPtr);
223 break;
224
225 case siSpeakerVolume:
226 D(bug(" set speaker volume %08lx\n", infoPtr));
227 audio_set_speaker_volume(infoPtr);
228 break;
229
230 case siHeadphoneMute:
231 case siHeadphoneVolume:
232 break;
233
234 case siHardwareMute:
235 audio_set_main_mute((uint16)infoPtr);
236 break;
237
238 case siHardwareVolume:
239 D(bug(" set hardware volume %08lx\n", infoPtr));
240 audio_set_main_volume(infoPtr);
241 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 return 0x00010003;
381
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 WriteMacInt32(audio_data + adatData + scd_format, AudioStatus.sample_size == 16 ? FOURCC('t','w','o','s') : FOURCC('r','a','w',' '));
408 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 }
473
474
475 /*
476 * Sound input driver Open() routine
477 */
478
479 int16 SoundInOpen(uint32 pb, uint32 dce)
480 {
481 D(bug("SoundInOpen\n"));
482 return noErr;
483 }
484
485
486 /*
487 * Sound input driver Prime() routine
488 */
489
490 int16 SoundInPrime(uint32 pb, uint32 dce)
491 {
492 D(bug("SoundInPrime\n"));
493 //!!
494 return paramErr;
495 }
496
497
498 /*
499 * Sound input driver Control() routine
500 */
501
502 int16 SoundInControl(uint32 pb, uint32 dce)
503 {
504 uint16 code = ReadMacInt16(pb + csCode);
505 D(bug("SoundInControl %d\n", code));
506
507 if (code == 1) {
508 D(bug(" SoundInKillIO\n"));
509 //!!
510 return noErr;
511 }
512
513 if (code != 2)
514 return -231; // siUnknownInfoType
515
516 uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
517 uint32 selector = param[0];
518 D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
519
520 switch (selector) {
521 default:
522 return -231; // siUnknownInfoType
523 }
524 }
525
526
527 /*
528 * Sound input driver Status() routine
529 */
530
531 int16 SoundInStatus(uint32 pb, uint32 dce)
532 {
533 uint16 code = ReadMacInt16(pb + csCode);
534 D(bug("SoundInStatus %d\n", code));
535 if (code != 2)
536 return -231; // siUnknownInfoType
537
538 uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
539 uint32 selector = param[0];
540 D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
541 switch (selector) {
542 #if 0
543 case siDeviceName: {
544 const char *str = GetString(STR_SOUND_IN_NAME);
545 param[0] = 0;
546 memcpy((void *)param[1], str, strlen(str));
547 return noErr;
548 }
549
550 case siDeviceIcon: {
551 M68kRegisters r;
552 static const uint16 proc[] = {
553 0x558f, // subq.l #2,sp
554 0xa994, // CurResFile
555 0x4267, // clr.w -(sp)
556 0xa998, // UseResFile
557 0x598f, // subq.l #4,sp
558 0x4879, 0x4943, 0x4e23, // move.l #'ICN#',-(sp)
559 0x3f3c, 0xbf76, // move.w #-16522,-(sp)
560 0xa9a0, // GetResource
561 0x245f, // move.l (sp)+,a2
562 0xa998, // UseResFile
563 0x200a, // move.l a2,d0
564 0x6604, // bne 1
565 0x7000, // moveq #0,d0
566 M68K_RTS,
567 0x2f0a, //1 move.l a2,-(sp)
568 0xa992, // DetachResource
569 0x204a, // move.l a2,a0
570 0xa04a, // HNoPurge
571 0x7001, // moveq #1,d0
572 M68K_RTS
573 };
574 Execute68k((uint32)proc, &r);
575 if (r.d[0]) {
576 param[0] = 4; // Length of returned data
577 param[1] = r.a[2]; // Handle to icon suite
578 return noErr;
579 } else
580 return -192; // resNotFound
581 }
582 #endif
583 default:
584 return -231; // siUnknownInfoType
585 }
586 }
587
588
589 /*
590 * Sound input driver Close() routine
591 */
592
593 int16 SoundInClose(uint32 pb, uint32 dce)
594 {
595 D(bug("SoundInClose\n"));
596 return noErr;
597 }