ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/audio.cpp
Revision: 1.8
Committed: 2001-07-05T20:30:49Z (22 years, 11 months ago) by cebix
Branch: MAIN
Changes since 1.7: +35 -18 lines
Log Message:
- supported audio formats are now kept in STL vectors
- added run-time audio parameter switching for OSS/ESD audio output
- setting ESPEAKER env variable causes B2 to try ESD before OSS

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * audio.cpp - Audio support
3     *
4 cebix 1.7 * Basilisk II (C) 1997-2001 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 cebix 1.8 // Supported sample rates, sizes and channels
40     vector<uint32> audio_sample_rates;
41     vector<uint16> audio_sample_sizes;
42     vector<uint16> audio_channel_counts;
43    
44 cebix 1.1 // Global variables
45     struct audio_status AudioStatus; // Current audio status (sample rate etc.)
46     bool audio_open = false; // Flag: audio is initialized and ready
47     int audio_frames_per_block; // Number of audio frames per block
48     uint32 audio_component_flags; // Component feature flags
49     uint32 audio_data = 0; // Mac address of global data area
50     static int open_count = 0; // Open/close nesting count
51    
52     bool AudioAvailable = false; // Flag: audio output available (from the software point of view)
53    
54    
55     /*
56 cebix 1.4 * Reset audio emulation
57     */
58    
59     void AudioReset(void)
60     {
61     audio_data = 0;
62     }
63    
64    
65     /*
66 cebix 1.1 * Get audio info
67     */
68    
69     static int32 AudioGetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
70     {
71     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));
72     M68kRegisters r;
73     int i;
74    
75     switch (selector) {
76     case siSampleSize:
77     WriteMacInt16(infoPtr, AudioStatus.sample_size);
78     break;
79    
80     case siSampleSizeAvailable: {
81 cebix 1.8 r.d[0] = audio_sample_sizes.size() * 2;
82 cebix 1.1 Execute68kTrap(0xa122, &r); // NewHandle()
83     uint32 h = r.a[0];
84     if (h == 0)
85     return memFullErr;
86 cebix 1.8 WriteMacInt16(infoPtr + sil_count, audio_sample_sizes.size());
87 cebix 1.1 WriteMacInt32(infoPtr + sil_infoHandle, h);
88     uint32 sp = ReadMacInt32(h);
89 cebix 1.8 for (i=0; i<audio_sample_sizes.size(); i++)
90 cebix 1.1 WriteMacInt16(sp + i*2, audio_sample_sizes[i]);
91     break;
92     }
93    
94     case siNumberChannels:
95     WriteMacInt16(infoPtr, AudioStatus.channels);
96     break;
97    
98     case siChannelAvailable: {
99 cebix 1.8 r.d[0] = audio_channel_counts.size() * 2;
100 cebix 1.1 Execute68kTrap(0xa122, &r); // NewHandle()
101     uint32 h = r.a[0];
102     if (h == 0)
103     return memFullErr;
104 cebix 1.8 WriteMacInt16(infoPtr + sil_count, audio_channel_counts.size());
105 cebix 1.1 WriteMacInt32(infoPtr + sil_infoHandle, h);
106     uint32 sp = ReadMacInt32(h);
107 cebix 1.8 for (i=0; i<audio_channel_counts.size(); i++)
108 cebix 1.1 WriteMacInt16(sp + i*2, audio_channel_counts[i]);
109     break;
110     }
111    
112     case siSampleRate:
113     WriteMacInt32(infoPtr, AudioStatus.sample_rate);
114     break;
115    
116     case siSampleRateAvailable: {
117 cebix 1.8 r.d[0] = audio_sample_rates.size() * 4;
118 cebix 1.1 Execute68kTrap(0xa122, &r); // NewHandle()
119     uint32 h = r.a[0];
120     if (h == 0)
121     return memFullErr;
122 cebix 1.8 WriteMacInt16(infoPtr + sil_count, audio_sample_rates.size());
123 cebix 1.1 WriteMacInt32(infoPtr + sil_infoHandle, h);
124     uint32 lp = ReadMacInt32(h);
125 cebix 1.8 for (i=0; i<audio_sample_rates.size(); i++)
126 cebix 1.1 WriteMacInt32(lp + i*4, audio_sample_rates[i]);
127     break;
128     }
129    
130     case siSpeakerMute:
131 cebix 1.2 WriteMacInt16(infoPtr, audio_get_speaker_mute());
132 cebix 1.1 break;
133    
134     case siSpeakerVolume:
135 cebix 1.2 WriteMacInt32(infoPtr, audio_get_speaker_volume());
136     break;
137    
138     case siHeadphoneMute:
139     WriteMacInt16(infoPtr, 0);
140     break;
141    
142     case siHeadphoneVolume:
143     WriteMacInt32(infoPtr, 0x01000100);
144     break;
145    
146     case siHeadphoneVolumeSteps:
147     WriteMacInt16(infoPtr, 13);
148 cebix 1.1 break;
149    
150     case siHardwareMute:
151 cebix 1.2 WriteMacInt16(infoPtr, audio_get_main_mute());
152 cebix 1.1 break;
153    
154     case siHardwareVolume:
155 cebix 1.2 WriteMacInt32(infoPtr, audio_get_main_volume());
156     break;
157    
158     case siHardwareVolumeSteps:
159     WriteMacInt16(infoPtr, 13);
160 cebix 1.1 break;
161    
162     case siHardwareBusy:
163     WriteMacInt16(infoPtr, AudioStatus.num_sources != 0);
164     break;
165    
166     default: // Delegate to Apple Mixer
167     if (AudioStatus.mixer == 0)
168     return badComponentSelector;
169     M68kRegisters r;
170     r.a[0] = infoPtr;
171     r.d[0] = selector;
172     r.a[1] = sourceID;
173     r.a[2] = AudioStatus.mixer;
174     Execute68k(audio_data + adatGetInfo, &r);
175     D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
176     return r.d[0];
177     }
178     return noErr;
179     }
180    
181    
182     /*
183     * Set audio info
184     */
185    
186     static int32 AudioSetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID)
187     {
188     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));
189     M68kRegisters r;
190     int i;
191    
192     switch (selector) {
193     case siSampleSize:
194     D(bug(" set sample size %08lx\n", infoPtr));
195     if (AudioStatus.num_sources)
196     return siDeviceBusyErr;
197 cebix 1.8 if (infoPtr == AudioStatus.sample_size)
198     return noErr;
199     for (i=0; i<audio_sample_sizes.size(); i++)
200 cebix 1.1 if (audio_sample_sizes[i] == infoPtr) {
201 cebix 1.8 if (audio_set_sample_size(i))
202     return noErr;
203     else
204     return siInvalidSampleSize;
205 cebix 1.1 }
206     return siInvalidSampleSize;
207    
208     case siSampleRate:
209     D(bug(" set sample rate %08lx\n", infoPtr));
210     if (AudioStatus.num_sources)
211     return siDeviceBusyErr;
212 cebix 1.8 if (infoPtr == AudioStatus.sample_rate)
213     return noErr;
214     for (i=0; i<audio_sample_rates.size(); i++)
215 cebix 1.1 if (audio_sample_rates[i] == infoPtr) {
216 cebix 1.8 if (audio_set_sample_rate(i))
217     return noErr;
218     else
219     return siInvalidSampleRate;
220 cebix 1.1 }
221     return siInvalidSampleRate;
222    
223     case siNumberChannels:
224     D(bug(" set number of channels %08lx\n", infoPtr));
225     if (AudioStatus.num_sources)
226     return siDeviceBusyErr;
227 cebix 1.8 if (infoPtr == AudioStatus.channels)
228     return noErr;
229     for (i=0; i<audio_channel_counts.size(); i++)
230 cebix 1.1 if (audio_channel_counts[i] == infoPtr) {
231 cebix 1.8 if (audio_set_channels(i))
232     return noErr;
233     else
234     return badChannel;
235 cebix 1.1 }
236     return badChannel;
237    
238     case siSpeakerMute:
239 cebix 1.2 audio_set_speaker_mute((uint16)infoPtr);
240 cebix 1.1 break;
241    
242     case siSpeakerVolume:
243     D(bug(" set speaker volume %08lx\n", infoPtr));
244 cebix 1.2 audio_set_speaker_volume(infoPtr);
245     break;
246    
247     case siHeadphoneMute:
248     case siHeadphoneVolume:
249 cebix 1.1 break;
250    
251     case siHardwareMute:
252 cebix 1.2 audio_set_main_mute((uint16)infoPtr);
253 cebix 1.1 break;
254    
255     case siHardwareVolume:
256     D(bug(" set hardware volume %08lx\n", infoPtr));
257 cebix 1.2 audio_set_main_volume(infoPtr);
258 cebix 1.1 break;
259    
260     default: // Delegate to Apple Mixer
261     if (AudioStatus.mixer == 0)
262     return badComponentSelector;
263     r.a[0] = infoPtr;
264     r.d[0] = selector;
265     r.a[1] = sourceID;
266     r.a[2] = AudioStatus.mixer;
267     Execute68k(audio_data + adatSetInfo, &r);
268     D(bug(" delegated to Apple Mixer, returns %08lx\n", r.d[0]));
269     return r.d[0];
270     }
271     return noErr;
272     }
273    
274    
275     /*
276     * Sound output component dispatch
277     */
278    
279     int32 AudioDispatch(uint32 params, uint32 globals)
280     {
281     D(bug("AudioDispatch params %08lx (size %d), what %d\n", params, ReadMacInt8(params + cp_paramSize), (int16)ReadMacInt16(params + cp_what)));
282     M68kRegisters r;
283     uint32 p = params + cp_params;
284    
285     switch ((int16)ReadMacInt16(params + cp_what)) {
286     // Basic component functions
287     case kComponentOpenSelect:
288     if (audio_data == 0) {
289    
290     // Allocate global data area
291     r.d[0] = SIZEOF_adat;
292     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
293     if (r.a[0] == 0)
294     return memFullErr;
295     audio_data = r.a[0];
296     D(bug(" global data at %08lx\n", audio_data));
297    
298     // Put in 68k routines
299     int p = audio_data + adatDelegateCall;
300     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
301     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
302     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
303     WriteMacInt16(p, 0x7024); p += 2; // moveq #$24,d0
304     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
305     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
306     WriteMacInt16(p, M68K_RTS); p += 2; // rts
307     if (p - audio_data != adatOpenMixer)
308     goto adat_error;
309     WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
310     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
311     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
312     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
313     WriteMacInt16(p, 0x203c); p += 2; // move.l #$06140018,d0
314     WriteMacInt32(p, 0x06140018); p+= 4;
315     WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
316     WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
317     WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
318     WriteMacInt16(p, M68K_RTS); p += 2; // rts
319     if (p - audio_data != adatCloseMixer)
320     goto adat_error;
321     WriteMacInt16(p, 0x558f); p += 2; // subq.l #2,sp
322     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
323     WriteMacInt16(p, 0x203c); p += 2; // move.l #$02180018,d0
324     WriteMacInt32(p, 0x02180018); p+= 4;
325     WriteMacInt16(p, 0xa800); p += 2; // SoundDispatch
326     WriteMacInt16(p, 0x301f); p += 2; // move.w (sp)+,d0
327     WriteMacInt16(p, 0x48c0); p += 2; // ext.l d0
328     WriteMacInt16(p, M68K_RTS); p += 2; // rts
329     if (p - audio_data != adatGetInfo)
330     goto adat_error;
331     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
332     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
333     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
334     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
335     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
336     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0103,-(sp)
337     WriteMacInt32(p, 0x000c0103); p+= 4;
338     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
339     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
340     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
341     WriteMacInt16(p, M68K_RTS); p += 2; // rts
342     if (p - audio_data != adatSetInfo)
343     goto adat_error;
344     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
345     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
346     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
347     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
348     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
349     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0104,-(sp)
350     WriteMacInt32(p, 0x000c0104); p+= 4;
351     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
352     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
353     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
354     WriteMacInt16(p, M68K_RTS); p += 2; // rts
355     if (p - audio_data != adatPlaySourceBuffer)
356     goto adat_error;
357     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
358     WriteMacInt16(p, 0x2f0a); p += 2; // move.l a2,-(sp)
359     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
360     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
361     WriteMacInt16(p, 0x2f00); p += 2; // move.l d0,-(sp)
362     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$000c0108,-(sp)
363     WriteMacInt32(p, 0x000c0108); p+= 4;
364     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
365     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
366     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
367     WriteMacInt16(p, M68K_RTS); p += 2; // rts
368     if (p - audio_data != adatGetSourceData)
369     goto adat_error;
370     WriteMacInt16(p, 0x598f); p += 2; // subq.l #4,sp
371     WriteMacInt16(p, 0x2f09); p += 2; // move.l a1,-(sp)
372     WriteMacInt16(p, 0x2f08); p += 2; // move.l a0,-(sp)
373     WriteMacInt16(p, 0x2f3c); p += 2; // move.l #$00040004,-(sp)
374     WriteMacInt32(p, 0x00040004); p+= 4;
375     WriteMacInt16(p, 0x7000); p += 2; // moveq #0,d0
376     WriteMacInt16(p, 0xa82a); p += 2; // ComponentDispatch
377     WriteMacInt16(p, 0x201f); p += 2; // move.l (sp)+,d0
378     WriteMacInt16(p, M68K_RTS); p += 2; // rts
379     if (p - audio_data != adatData)
380     goto adat_error;
381     }
382     AudioAvailable = true;
383     if (open_count == 0)
384     audio_enter_stream();
385     open_count++;
386     return noErr;
387    
388     adat_error: printf("FATAL: audio component data block initialization error\n");
389     QuitEmulator();
390     return openErr;
391    
392     case kComponentCanDoSelect:
393     case kComponentRegisterSelect:
394     return noErr;
395    
396     case kComponentVersionSelect:
397 cebix 1.2 return 0x00010003;
398 cebix 1.1
399     case kComponentCloseSelect:
400     open_count--;
401     if (open_count == 0) {
402     if (AudioStatus.mixer) {
403     // Close Apple Mixer
404     r.a[0] = AudioStatus.mixer;
405     Execute68k(audio_data + adatCloseMixer, &r);
406     AudioStatus.mixer = 0;
407     return r.d[0];
408     }
409     AudioStatus.num_sources = 0;
410     audio_exit_stream();
411     }
412     return noErr;
413    
414     // Sound component functions
415     case kSoundComponentInitOutputDeviceSelect:
416     D(bug(" InitOutputDevice\n"));
417     if (!audio_open)
418     return noHardwareErr;
419     if (AudioStatus.mixer)
420     return noErr;
421    
422     // Init sound component data
423     WriteMacInt32(audio_data + adatData + scd_flags, 0);
424 cebix 1.5 WriteMacInt32(audio_data + adatData + scd_format, AudioStatus.sample_size == 16 ? FOURCC('t','w','o','s') : FOURCC('r','a','w',' '));
425 cebix 1.1 WriteMacInt16(audio_data + adatData + scd_numChannels, AudioStatus.channels);
426     WriteMacInt16(audio_data + adatData + scd_sampleSize, AudioStatus.sample_size);
427     WriteMacInt32(audio_data + adatData + scd_sampleRate, AudioStatus.sample_rate);
428     WriteMacInt32(audio_data + adatData + scd_sampleCount, audio_frames_per_block);
429     WriteMacInt32(audio_data + adatData + scd_buffer, 0);
430     WriteMacInt32(audio_data + adatData + scd_reserved, 0);
431     WriteMacInt32(audio_data + adatStreamInfo, 0);
432    
433     // Open Apple Mixer
434     r.a[0] = audio_data + adatMixer;
435     r.d[0] = 0;
436     r.a[1] = audio_data + adatData;
437     Execute68k(audio_data + adatOpenMixer, &r);
438     AudioStatus.mixer = ReadMacInt32(audio_data + adatMixer);
439     D(bug(" OpenMixer() returns %08lx, mixer %08lx\n", r.d[0], AudioStatus.mixer));
440     return r.d[0];
441    
442     case kSoundComponentAddSourceSelect:
443     D(bug(" AddSource\n"));
444     AudioStatus.num_sources++;
445     goto delegate;
446    
447     case kSoundComponentRemoveSourceSelect:
448     D(bug(" RemoveSource\n"));
449     AudioStatus.num_sources--;
450     goto delegate;
451    
452     case kSoundComponentStopSourceSelect:
453     D(bug(" StopSource\n"));
454     goto delegate;
455    
456     case kSoundComponentPauseSourceSelect:
457     D(bug(" PauseSource\n"));
458     delegate: // Delegate call to Apple Mixer
459     D(bug(" delegating call to Apple Mixer\n"));
460     r.a[0] = AudioStatus.mixer;
461     r.a[1] = params;
462     Execute68k(audio_data + adatDelegateCall, &r);
463     D(bug(" returns %08lx\n", r.d[0]));
464     return r.d[0];
465    
466     case kSoundComponentStartSourceSelect:
467     D(bug(" StartSource\n"));
468     return noErr;
469    
470     case kSoundComponentGetInfoSelect:
471     return AudioGetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
472    
473     case kSoundComponentSetInfoSelect:
474     return AudioSetInfo(ReadMacInt32(p), ReadMacInt32(p + 4), ReadMacInt32(p + 8));
475    
476     case kSoundComponentPlaySourceBufferSelect:
477     D(bug(" PlaySourceBuffer\n"));
478     r.d[0] = ReadMacInt32(p);
479     r.a[0] = ReadMacInt32(p + 4);
480     r.a[1] = ReadMacInt32(p + 8);
481     r.a[2] = AudioStatus.mixer;
482     Execute68k(audio_data + adatPlaySourceBuffer, &r);
483     D(bug(" returns %08lx\n", r.d[0]));
484     return r.d[0];
485    
486     default:
487     return badComponentSelector;
488     }
489     }
490 cebix 1.6
491    
492     /*
493     * Sound input driver Open() routine
494     */
495    
496     int16 SoundInOpen(uint32 pb, uint32 dce)
497     {
498     D(bug("SoundInOpen\n"));
499     return noErr;
500     }
501    
502    
503     /*
504     * Sound input driver Prime() routine
505     */
506    
507     int16 SoundInPrime(uint32 pb, uint32 dce)
508     {
509     D(bug("SoundInPrime\n"));
510     //!!
511     return paramErr;
512     }
513    
514    
515     /*
516     * Sound input driver Control() routine
517     */
518    
519     int16 SoundInControl(uint32 pb, uint32 dce)
520     {
521     uint16 code = ReadMacInt16(pb + csCode);
522     D(bug("SoundInControl %d\n", code));
523    
524     if (code == 1) {
525     D(bug(" SoundInKillIO\n"));
526     //!!
527     return noErr;
528     }
529    
530     if (code != 2)
531     return -231; // siUnknownInfoType
532    
533     uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
534     uint32 selector = param[0];
535     D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
536    
537     switch (selector) {
538     default:
539     return -231; // siUnknownInfoType
540     }
541     }
542    
543    
544     /*
545     * Sound input driver Status() routine
546     */
547    
548     int16 SoundInStatus(uint32 pb, uint32 dce)
549     {
550     uint16 code = ReadMacInt16(pb + csCode);
551     D(bug("SoundInStatus %d\n", code));
552     if (code != 2)
553     return -231; // siUnknownInfoType
554    
555     uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam);
556     uint32 selector = param[0];
557     D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector));
558     switch (selector) {
559     #if 0
560     case siDeviceName: {
561     const char *str = GetString(STR_SOUND_IN_NAME);
562     param[0] = 0;
563     memcpy((void *)param[1], str, strlen(str));
564     return noErr;
565     }
566    
567     case siDeviceIcon: {
568     M68kRegisters r;
569     static const uint16 proc[] = {
570     0x558f, // subq.l #2,sp
571     0xa994, // CurResFile
572     0x4267, // clr.w -(sp)
573     0xa998, // UseResFile
574     0x598f, // subq.l #4,sp
575     0x4879, 0x4943, 0x4e23, // move.l #'ICN#',-(sp)
576     0x3f3c, 0xbf76, // move.w #-16522,-(sp)
577     0xa9a0, // GetResource
578     0x245f, // move.l (sp)+,a2
579     0xa998, // UseResFile
580     0x200a, // move.l a2,d0
581     0x6604, // bne 1
582     0x7000, // moveq #0,d0
583     M68K_RTS,
584     0x2f0a, //1 move.l a2,-(sp)
585     0xa992, // DetachResource
586     0x204a, // move.l a2,a0
587     0xa04a, // HNoPurge
588     0x7001, // moveq #1,d0
589     M68K_RTS
590     };
591     Execute68k((uint32)proc, &r);
592     if (r.d[0]) {
593     param[0] = 4; // Length of returned data
594     param[1] = r.a[2]; // Handle to icon suite
595     return noErr;
596     } else
597     return -192; // resNotFound
598     }
599     #endif
600     default:
601     return -231; // siUnknownInfoType
602     }
603     }
604    
605    
606     /*
607     * Sound input driver Close() routine
608     */
609    
610     int16 SoundInClose(uint32 pb, uint32 dce)
611     {
612     D(bug("SoundInClose\n"));
613     return noErr;
614     }