~ubuntu-branches/ubuntu/trusty/basilisk2/trusty

« back to all changes in this revision

Viewing changes to src/AmigaOS/audio_amiga.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2003-07-24 00:48:57 UTC
  • Revision ID: james.westby@ubuntu.com-20030724004857-vnv33v6vf7a7u0z6
Tags: upstream-0.9.20030722
ImportĀ upstreamĀ versionĀ 0.9.20030722

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  audio_amiga.cpp - Audio support, AmigaOS implementation using AHI
 
3
 *
 
4
 *  Basilisk II (C) 1997-2001 Christian Bauer
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
 
 
21
#include "sysdeps.h"
 
22
 
 
23
#include <exec/types.h>
 
24
#include <exec/memory.h>
 
25
#include <devices/ahi.h>
 
26
#define __USE_SYSBASE
 
27
#include <proto/exec.h>
 
28
#include <proto/ahi.h>
 
29
#include <inline/exec.h>
 
30
#include <inline/ahi.h>
 
31
 
 
32
#include "cpu_emulation.h"
 
33
#include "main.h"
 
34
#include "prefs.h"
 
35
#include "user_strings.h"
 
36
#include "audio.h"
 
37
#include "audio_defs.h"
 
38
 
 
39
#define DEBUG 0
 
40
#include "debug.h"
 
41
 
 
42
#define D1(x) ;
 
43
 
 
44
 
 
45
// Global variables
 
46
static ULONG ahi_id = AHI_DEFAULT_ID;                   // AHI audio ID
 
47
static struct AHIAudioCtrl *ahi_ctrl = NULL;
 
48
static struct AHISampleInfo sample[2];                  // Two sample infos for double-buffering
 
49
static struct Hook sf_hook;
 
50
static int play_buf = 0;                                                // Number of currently played buffer
 
51
static long sound_buffer_size;                                  // Size of one audio buffer in bytes
 
52
static int audio_block_fetched = 0;                             // Number of audio blocks fetched by interrupt routine
 
53
 
 
54
static bool main_mute = false;
 
55
static bool speaker_mute = false;
 
56
static ULONG supports_volume_changes = false;
 
57
static ULONG supports_stereo_panning = false;
 
58
static ULONG current_main_volume;
 
59
static ULONG current_speaker_volume;
 
60
 
 
61
 
 
62
// Prototypes
 
63
static __saveds __attribute__((regparm(3))) ULONG audio_callback(struct Hook *hook /*a0*/, struct AHISoundMessage *msg /*a1*/, struct AHIAudioCtrl *ahi_ctrl /*a2*/);
 
64
void audio_set_sample_rate_byval(uint32 value);
 
65
void audio_set_sample_size_byval(uint32 value);
 
66
void audio_set_channels_byval(uint32 value);
 
67
 
 
68
 
 
69
/*
 
70
 *  Initialization
 
71
 */
 
72
 
 
73
// Set AudioStatus to reflect current audio stream format
 
74
static void set_audio_status_format(int sample_rate_index)
 
75
{
 
76
        AudioStatus.sample_rate = audio_sample_rates[sample_rate_index];
 
77
        AudioStatus.sample_size = audio_sample_sizes[0];
 
78
        AudioStatus.channels = audio_channel_counts[0];
 
79
}
 
80
 
 
81
void AudioInit(void)
 
82
{
 
83
        sample[0].ahisi_Address = sample[1].ahisi_Address = NULL;
 
84
 
 
85
        // Init audio status and feature flags
 
86
        audio_channel_counts.push_back(2);
 
87
//      set_audio_status_format();
 
88
        AudioStatus.mixer = 0;
 
89
        AudioStatus.num_sources = 0;
 
90
        audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
 
91
 
 
92
        // Sound disabled in prefs? Then do nothing
 
93
        if (PrefsFindBool("nosound"))
 
94
                return;
 
95
 
 
96
        // AHI available?
 
97
        if (AHIBase == NULL) {
 
98
                WarningAlert(GetString(STR_NO_AHI_WARN));
 
99
                return;
 
100
        }
 
101
 
 
102
        // Initialize callback hook
 
103
        sf_hook.h_Entry = (HOOKFUNC)audio_callback;
 
104
 
 
105
        // Read "sound" preferences
 
106
        const char *str = PrefsFindString("sound");
 
107
        if (str)
 
108
                sscanf(str, "ahi/%08lx", &ahi_id);
 
109
 
 
110
        // Open audio control structure
 
111
        if ((ahi_ctrl = AHI_AllocAudio(
 
112
                AHIA_AudioID, ahi_id,
 
113
                AHIA_MixFreq, AudioStatus.sample_rate >> 16,
 
114
                AHIA_Channels, 1,
 
115
                AHIA_Sounds, 2,
 
116
                AHIA_SoundFunc, (ULONG)&sf_hook,
 
117
                TAG_END)) == NULL) {
 
118
                WarningAlert(GetString(STR_NO_AHI_CTRL_WARN));
 
119
                return;
 
120
        }
 
121
 
 
122
        ULONG max_channels, sample_rate, frequencies, sample_rate_index;
 
123
 
 
124
        AHI_GetAudioAttrs(ahi_id, ahi_ctrl,
 
125
                AHIDB_MaxChannels, (ULONG) &max_channels,
 
126
                AHIDB_Frequencies, (ULONG) &frequencies,
 
127
                TAG_END);
 
128
 
 
129
        D(bug("AudioInit: max_channels=%ld frequencies=%ld\n", max_channels, frequencies));
 
130
 
 
131
        for (int n=0; n<frequencies; n++)
 
132
                {
 
133
                AHI_GetAudioAttrs(ahi_id, ahi_ctrl,
 
134
                        AHIDB_FrequencyArg, n,
 
135
                        AHIDB_Frequency, (ULONG) &sample_rate,
 
136
                        TAG_END);
 
137
 
 
138
                D(bug("AudioInit: f=%ld Hz\n", sample_rate));
 
139
                audio_sample_rates.push_back(sample_rate << 16);
 
140
                }
 
141
 
 
142
        ULONG sample_size_bits = 16;
 
143
 
 
144
        D(bug("AudioInit: sampe_rates=%ld\n", audio_sample_rates.size() ));
 
145
 
 
146
        // get index of sample rate closest to 22050 Hz
 
147
        AHI_GetAudioAttrs(ahi_id, ahi_ctrl,
 
148
                AHIDB_IndexArg, 22050,
 
149
                AHIDB_Bits, (ULONG) &sample_size_bits,
 
150
                AHIDB_Index, (ULONG) &sample_rate_index,
 
151
                AHIDB_Volume, (ULONG) &supports_volume_changes,
 
152
                AHIDB_Panning, (ULONG) &supports_stereo_panning,
 
153
                TAG_END);
 
154
 
 
155
        audio_sample_sizes.push_back(16);
 
156
 
 
157
        set_audio_status_format(sample_rate_index);
 
158
 
 
159
        // 2048 frames per block
 
160
        audio_frames_per_block = 2048;
 
161
        sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
 
162
 
 
163
        // Prepare SampleInfos and load sounds (two sounds for double buffering)
 
164
        sample[0].ahisi_Type = AudioStatus.sample_size == 16 ? AHIST_S16S : AHIST_S8S;
 
165
        sample[0].ahisi_Length = audio_frames_per_block;
 
166
        sample[0].ahisi_Address = AllocVec(sound_buffer_size, MEMF_PUBLIC | MEMF_CLEAR);
 
167
        sample[1].ahisi_Type = AudioStatus.sample_size == 16 ? AHIST_S16S : AHIST_S8S;
 
168
        sample[1].ahisi_Length = audio_frames_per_block;
 
169
        sample[1].ahisi_Address = AllocVec(sound_buffer_size, MEMF_PUBLIC | MEMF_CLEAR);
 
170
        if (sample[0].ahisi_Address == NULL || sample[1].ahisi_Address == NULL)
 
171
                return;
 
172
 
 
173
        AHI_LoadSound(0, AHIST_DYNAMICSAMPLE, &sample[0], ahi_ctrl);
 
174
        AHI_LoadSound(1, AHIST_DYNAMICSAMPLE, &sample[1], ahi_ctrl);
 
175
 
 
176
        // Set parameters
 
177
        play_buf = 0;
 
178
        current_main_volume = current_speaker_volume = 0x10000;
 
179
        AHI_SetVol(0, current_speaker_volume, 0x8000, ahi_ctrl, AHISF_IMM);
 
180
 
 
181
        AHI_SetFreq(0, AudioStatus.sample_rate >> 16, ahi_ctrl, AHISF_IMM);
 
182
        AHI_SetSound(0, play_buf, 0, 0, ahi_ctrl, AHISF_IMM);
 
183
 
 
184
        // Everything OK
 
185
        audio_open = true;
 
186
}
 
187
 
 
188
 
 
189
/*
 
190
 *  Deinitialization
 
191
 */
 
192
 
 
193
void AudioExit(void)
 
194
{
 
195
        // Free everything
 
196
        if (ahi_ctrl != NULL) {
 
197
                AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_END);
 
198
                AHI_FreeAudio(ahi_ctrl);
 
199
        }
 
200
 
 
201
        FreeVec(sample[0].ahisi_Address);
 
202
        FreeVec(sample[1].ahisi_Address);
 
203
}
 
204
 
 
205
 
 
206
/*
 
207
 *  First source added, start audio stream
 
208
 */
 
209
 
 
210
void audio_enter_stream()
 
211
{
 
212
        AHI_ControlAudio(ahi_ctrl, AHIC_Play, TRUE, TAG_END);
 
213
}
 
214
 
 
215
 
 
216
/*
 
217
 *  Last source removed, stop audio stream
 
218
 */
 
219
 
 
220
void audio_exit_stream()
 
221
{
 
222
        AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_END);
 
223
}
 
224
 
 
225
 
 
226
/*
 
227
 *  AHI sound callback, request next buffer
 
228
 */
 
229
 
 
230
static __saveds __attribute__((regparm(3))) ULONG audio_callback(struct Hook *hook /*a0*/, struct AHISoundMessage *msg /*a1*/, struct AHIAudioCtrl *ahi_ctrl /*a2*/)
 
231
{
 
232
        play_buf ^= 1;
 
233
 
 
234
        // New buffer available?
 
235
        if (audio_block_fetched)
 
236
                {
 
237
                audio_block_fetched--;
 
238
 
 
239
                if (main_mute || speaker_mute)
 
240
                        {
 
241
                        memset(sample[play_buf].ahisi_Address, 0, sound_buffer_size);
 
242
                        }
 
243
                else
 
244
                        {
 
245
                        // Get size of audio data
 
246
                        uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
 
247
                        if (apple_stream_info) {
 
248
                                int32 sample_count = ReadMacInt32(apple_stream_info + scd_sampleCount);
 
249
 
 
250
                                uint32 num_channels = ReadMacInt16(apple_stream_info + scd_numChannels);
 
251
                                uint32 sample_size = ReadMacInt16(apple_stream_info + scd_sampleSize);
 
252
                                uint32 sample_rate = ReadMacInt32(apple_stream_info + scd_sampleRate);
 
253
 
 
254
                                D(bug("stream: sample_count=%ld  num_channels=%ld  sample_size=%ld  sample_rate=%ld\n", sample_count, num_channels, sample_size, sample_rate >> 16));
 
255
 
 
256
                                // Yes, this can happen.
 
257
                                if(sample_count != 0) {
 
258
                                        if(sample_rate != AudioStatus.sample_rate) {
 
259
                                                audio_set_sample_rate_byval(sample_rate);
 
260
                                        }
 
261
                                        if(num_channels != AudioStatus.channels) {
 
262
                                                audio_set_channels_byval(num_channels);
 
263
                                        }
 
264
                                        if(sample_size != AudioStatus.sample_size) {
 
265
                                                audio_set_sample_size_byval(sample_size);
 
266
                                        }
 
267
                                }
 
268
 
 
269
                                if (sample_count < 0)
 
270
                                        sample_count = 0;
 
271
 
 
272
                                int work_size = sample_count * num_channels * (sample_size>>3);
 
273
                                D(bug("stream: work_size=%ld  sound_buffer_size=%ld\n", work_size, sound_buffer_size));
 
274
 
 
275
                                if (work_size > sound_buffer_size)
 
276
                                        work_size = sound_buffer_size;
 
277
 
 
278
                                // Put data into AHI buffer (convert 8-bit data unsigned->signed)
 
279
                                if (AudioStatus.sample_size == 16)
 
280
                                        Mac2Host_memcpy(sample[play_buf].ahisi_Address, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
 
281
                                else {
 
282
                                        uint32 *p = (uint32 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer));
 
283
                                        uint32 *q = (uint32 *)sample[play_buf].ahisi_Address;
 
284
                                        int r = work_size >> 2;
 
285
                                        while (r--)
 
286
                                                *q++ = *p++ ^ 0x80808080;
 
287
                                }
 
288
                                if (work_size != sound_buffer_size)
 
289
                                        memset((uint8 *)sample[play_buf].ahisi_Address + work_size, 0, sound_buffer_size - work_size);
 
290
                        }
 
291
                }
 
292
 
 
293
                }
 
294
        else
 
295
                memset(sample[play_buf].ahisi_Address, 0, sound_buffer_size);
 
296
 
 
297
        // Play next buffer
 
298
        AHI_SetSound(0, play_buf, 0, 0, ahi_ctrl, 0);
 
299
 
 
300
        // Trigger audio interrupt to get new buffer
 
301
        if (AudioStatus.num_sources) {
 
302
                D1(bug("stream: triggering irq\n"));
 
303
                SetInterruptFlag(INTFLAG_AUDIO);
 
304
                TriggerInterrupt();
 
305
        }
 
306
        return 0;
 
307
}
 
308
 
 
309
 
 
310
/*
 
311
 *  MacOS audio interrupt, read next data block
 
312
 */
 
313
 
 
314
void AudioInterrupt(void)
 
315
{
 
316
        D1(bug("AudioInterrupt\n"));
 
317
 
 
318
        // Get data from apple mixer
 
319
        if (AudioStatus.mixer) {
 
320
                M68kRegisters r;
 
321
                r.a[0] = audio_data + adatStreamInfo;
 
322
                r.a[1] = AudioStatus.mixer;
 
323
                Execute68k(audio_data + adatGetSourceData, &r);
 
324
                D1(bug(" GetSourceData() returns %08lx\n", r.d[0]));
 
325
        } else
 
326
                WriteMacInt32(audio_data + adatStreamInfo, 0);
 
327
 
 
328
        // Signal stream function
 
329
        audio_block_fetched++;
 
330
        D1(bug("AudioInterrupt done\n"));
 
331
}
 
332
 
 
333
 
 
334
/*
 
335
 *  Set sampling parameters
 
336
 *  "index" is an index into the audio_sample_rates[] etc. arrays
 
337
 *  It is guaranteed that AudioStatus.num_sources == 0
 
338
 */
 
339
 
 
340
void audio_set_sample_rate_byval(uint32 value)
 
341
{
 
342
        bool changed = (AudioStatus.sample_rate != value);
 
343
        if(changed)
 
344
                {
 
345
                ULONG sample_rate_index;
 
346
 
 
347
                // get index of sample rate closest to <value> Hz
 
348
                AHI_GetAudioAttrs(ahi_id, ahi_ctrl,
 
349
                        AHIDB_IndexArg, value >> 16,
 
350
                        AHIDB_Index, (ULONG) &sample_rate_index,
 
351
                        TAG_END);
 
352
 
 
353
                D(bug(" audio_set_sample_rate_byval requested rate=%ld Hz\n", value >> 16));
 
354
 
 
355
                AudioStatus.sample_rate = audio_sample_rates[sample_rate_index];
 
356
 
 
357
                AHI_SetFreq(0, AudioStatus.sample_rate >> 16, ahi_ctrl, 0);
 
358
                }
 
359
 
 
360
        D(bug(" audio_set_sample_rate_byval rate=%ld Hz\n", AudioStatus.sample_rate >> 16));
 
361
}
 
362
 
 
363
void audio_set_sample_size_byval(uint32 value)
 
364
{
 
365
        bool changed = (AudioStatus.sample_size != value);
 
366
        if(changed) {
 
367
//              AudioStatus.sample_size = value;
 
368
//              update_sound_parameters();
 
369
//              WritePrivateProfileInt( "Audio", "SampleSize", AudioStatus.sample_size, ini_file_name );
 
370
        }
 
371
        D(bug(" audio_set_sample_size_byval %d\n", AudioStatus.sample_size));
 
372
}
 
373
 
 
374
void audio_set_channels_byval(uint32 value)
 
375
{
 
376
        bool changed = (AudioStatus.channels != value);
 
377
        if(changed) {
 
378
//              AudioStatus.channels = value;
 
379
//              update_sound_parameters();
 
380
//              WritePrivateProfileInt( "Audio", "Channels", AudioStatus.channels, ini_file_name );
 
381
        }
 
382
        D(bug(" audio_set_channels_byval %d\n", AudioStatus.channels));
 
383
}
 
384
 
 
385
bool audio_set_sample_rate(int index)
 
386
{
 
387
        if(index >= 0 && index < audio_sample_rates.size() ) {
 
388
                audio_set_sample_rate_byval( audio_sample_rates[index] );
 
389
                D(bug(" audio_set_sample_rate index=%ld rate=%ld\n", index, AudioStatus.sample_rate >> 16));
 
390
        }
 
391
 
 
392
        return true;
 
393
}
 
394
 
 
395
bool audio_set_sample_size(int index)
 
396
{
 
397
        if(index >= 0 && index < audio_sample_sizes.size()  ) {
 
398
                audio_set_sample_size_byval( audio_sample_sizes[index] );
 
399
                D(bug(" audio_set_sample_size %d,%d\n", index,AudioStatus.sample_size));
 
400
        }
 
401
 
 
402
        return true;
 
403
}
 
404
 
 
405
bool audio_set_channels(int index)
 
406
{
 
407
        if(index >= 0 && index < audio_channel_counts.size()   ) {
 
408
                audio_set_channels_byval( audio_channel_counts[index] );
 
409
                D(bug(" audio_set_channels %d,%d\n", index,AudioStatus.channels));
 
410
        }
 
411
 
 
412
        return true;
 
413
}
 
414
 
 
415
 
 
416
/*
 
417
 *  Get/set volume controls (volume values received/returned have the left channel
 
418
 *  volume in the upper 16 bits and the right channel volume in the lower 16 bits;
 
419
 *  both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume"))
 
420
 */
 
421
 
 
422
bool audio_get_main_mute(void)
 
423
{
 
424
        D(bug("audio_get_main_mute:  mute=%ld\n", main_mute));
 
425
 
 
426
        return main_mute;
 
427
}
 
428
 
 
429
uint32 audio_get_main_volume(void)
 
430
{
 
431
        D(bug("audio_get_main_volume\n"));
 
432
 
 
433
                ULONG volume = current_main_volume >> 8;        // 0x10000 => 0x100
 
434
 
 
435
                D(bug("audio_get_main_volume: volume=%08lx\n", volume));
 
436
 
 
437
                return (volume << 16) + volume;
 
438
 
 
439
        return 0x01000100;
 
440
}
 
441
 
 
442
bool audio_get_speaker_mute(void)
 
443
{
 
444
        D(bug("audio_get_speaker_mute:  mute=%ld\n", speaker_mute));
 
445
 
 
446
        return speaker_mute;
 
447
}
 
448
 
 
449
uint32 audio_get_speaker_volume(void)
 
450
{
 
451
        D(bug("audio_get_speaker_volume: \n"));
 
452
 
 
453
        if (audio_open)
 
454
                {
 
455
                ULONG volume = current_speaker_volume >> 8;     // 0x10000 => 0x100
 
456
 
 
457
                D(bug("audio_get_speaker_volume: volume=%08lx\n", volume));
 
458
 
 
459
                return (volume << 16) + volume;
 
460
                }
 
461
 
 
462
        return 0x01000100;
 
463
}
 
464
 
 
465
void audio_set_main_mute(bool mute)
 
466
{
 
467
        D(bug("audio_set_main_mute: mute=%ld\n", mute));
 
468
 
 
469
        if (mute != main_mute)
 
470
                {
 
471
                main_mute = mute;
 
472
                }
 
473
}
 
474
 
 
475
void audio_set_main_volume(uint32 vol)
 
476
{
 
477
        D(bug("audio_set_main_volume: vol=%08lx\n", vol));
 
478
 
 
479
        if (audio_open && supports_volume_changes)
 
480
                {
 
481
                ULONG volume = 0x80 * ((vol >> 16) + (vol & 0xffff));
 
482
 
 
483
                D(bug("audio_set_main_volume: volume=%08lx\n", volume));
 
484
 
 
485
                current_main_volume = volume;
 
486
 
 
487
                AHI_SetVol(0, volume, 0x8000, ahi_ctrl, AHISF_IMM);
 
488
                }
 
489
}
 
490
 
 
491
void audio_set_speaker_mute(bool mute)
 
492
{
 
493
        D(bug("audio_set_speaker_mute: mute=%ld\n", mute));
 
494
 
 
495
        if (mute != speaker_mute)
 
496
                {
 
497
                speaker_mute = mute;
 
498
                }
 
499
}
 
500
 
 
501
void audio_set_speaker_volume(uint32 vol)
 
502
{
 
503
        D(bug("audio_set_speaker_volume: vol=%08lx\n", vol));
 
504
 
 
505
        if (audio_open && supports_volume_changes)
 
506
                {
 
507
                ULONG volume = 0x80 * ((vol >> 16) + (vol & 0xffff));
 
508
 
 
509
                D(bug("audio_set_speaker_volume: volume=%08lx\n", volume));
 
510
 
 
511
                current_speaker_volume = volume;
 
512
 
 
513
                AHI_SetVol(0, volume, 0x8000, ahi_ctrl, AHISF_IMM);
 
514
                }
 
515
}