1999-10-03 14:16:26 +00:00
|
|
|
/*
|
|
|
|
* audio_beos.cpp - Audio support, BeOS implementation
|
|
|
|
*
|
2000-04-10 18:53:46 +00:00
|
|
|
* Basilisk II (C) 1997-2000 Christian Bauer
|
1999-10-03 14:16:26 +00:00
|
|
|
* Portions (C) 1997-1999 Marc Hellwig
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sysdeps.h"
|
|
|
|
|
|
|
|
#include <KernelKit.h>
|
|
|
|
#include <MediaKit.h>
|
|
|
|
|
|
|
|
#include "cpu_emulation.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "prefs.h"
|
|
|
|
#include "user_strings.h"
|
|
|
|
#include "audio.h"
|
|
|
|
#include "audio_defs.h"
|
|
|
|
|
|
|
|
#define DEBUG 0
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
|
|
|
|
// Supported sample rates, sizes and channels
|
|
|
|
int audio_num_sample_rates = 1;
|
|
|
|
uint32 audio_sample_rates[] = {44100 << 16};
|
|
|
|
int audio_num_sample_sizes = 1;
|
|
|
|
uint16 audio_sample_sizes[] = {16};
|
|
|
|
int audio_num_channel_counts = 1;
|
|
|
|
uint16 audio_channel_counts[] = {2};
|
|
|
|
|
|
|
|
// Global variables
|
|
|
|
static int audio_irq_done_sem = -1; // Signal from interrupt to streaming thread: data block read
|
|
|
|
static BSoundPlayer *the_player;
|
|
|
|
|
|
|
|
// Prototypes
|
|
|
|
static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Audio manager thread (for calling media kit functions;
|
|
|
|
* this is not safe under R4 when running on the MacOS stack in kernel space)
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Message constants
|
|
|
|
const uint32 MSG_QUIT_AUDIO_MANAGER = 'quit';
|
|
|
|
const uint32 MSG_ENTER_STREAM = 'entr';
|
|
|
|
const uint32 MSG_EXIT_STREAM = 'exit';
|
|
|
|
const uint32 MSG_GET_VOLUME = 'getv';
|
|
|
|
const uint32 MSG_SET_VOLUME = 'setv';
|
|
|
|
|
|
|
|
static thread_id am_thread = -1;
|
|
|
|
static sem_id am_done_sem = -1;
|
|
|
|
|
|
|
|
static volatile float am_volume;
|
|
|
|
|
|
|
|
static status_t audio_manager(void *arg)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
// Receive message
|
|
|
|
thread_id sender;
|
|
|
|
uint32 code = receive_data(&sender, NULL, 0);
|
|
|
|
D(bug("Audio manager received %08lx\n", code));
|
|
|
|
switch (code) {
|
|
|
|
case MSG_QUIT_AUDIO_MANAGER:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case MSG_ENTER_STREAM:
|
|
|
|
the_player->Start();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSG_EXIT_STREAM:
|
|
|
|
the_player->Stop();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSG_GET_VOLUME:
|
|
|
|
am_volume = the_player->Volume();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MSG_SET_VOLUME:
|
|
|
|
the_player->SetVolume(am_volume);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Acknowledge
|
|
|
|
release_sem(am_done_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
void AudioInit(void)
|
|
|
|
{
|
|
|
|
// Init audio status and feature flags
|
|
|
|
AudioStatus.sample_rate = audio_sample_rates[0];
|
|
|
|
AudioStatus.sample_size = audio_sample_sizes[0];
|
|
|
|
AudioStatus.channels = audio_channel_counts[0];
|
|
|
|
AudioStatus.mixer = 0;
|
|
|
|
AudioStatus.num_sources = 0;
|
|
|
|
audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
|
|
|
|
|
|
|
|
// Sound disabled in prefs? Then do nothing
|
|
|
|
if (PrefsFindBool("nosound"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Init semaphores
|
|
|
|
audio_irq_done_sem = create_sem(0, "Audio IRQ Done");
|
|
|
|
am_done_sem = create_sem(0, "Audio Manager Done");
|
|
|
|
|
|
|
|
// Start audio manager thread
|
|
|
|
am_thread = spawn_thread(audio_manager, "Audio Manager", B_NORMAL_PRIORITY, NULL);
|
|
|
|
resume_thread(am_thread);
|
|
|
|
|
|
|
|
// Start stream
|
|
|
|
media_raw_audio_format format;
|
|
|
|
format.frame_rate = AudioStatus.sample_rate >> 16;
|
|
|
|
format.channel_count = AudioStatus.channels;
|
|
|
|
format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
|
|
|
format.byte_order = B_MEDIA_BIG_ENDIAN;
|
|
|
|
audio_frames_per_block = 4096;
|
|
|
|
size_t block_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
|
|
|
|
D(bug("AudioInit: block size %d\n", block_size));
|
|
|
|
format.buffer_size = block_size;
|
|
|
|
the_player = new BSoundPlayer(&format, "MacOS Audio", playbuffer_func, NULL, NULL);
|
|
|
|
if (the_player->InitCheck() != B_NO_ERROR) {
|
|
|
|
printf("FATAL: Cannot initialize BSoundPlayer\n");
|
|
|
|
delete the_player;
|
|
|
|
the_player = NULL;
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
the_player->SetHasData(true);
|
|
|
|
|
|
|
|
// Everything OK
|
|
|
|
audio_open = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deinitialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
void AudioExit(void)
|
|
|
|
{
|
|
|
|
// Stop stream
|
|
|
|
if (the_player) {
|
|
|
|
the_player->Stop();
|
|
|
|
delete the_player;
|
|
|
|
the_player = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop audio manager
|
|
|
|
if (am_thread > 0) {
|
|
|
|
status_t l;
|
|
|
|
send_data(am_thread, MSG_QUIT_AUDIO_MANAGER, NULL, 0);
|
|
|
|
wait_for_thread(am_thread, &l);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete semaphores
|
|
|
|
delete_sem(am_done_sem);
|
|
|
|
delete_sem(audio_irq_done_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First source added, start audio stream
|
|
|
|
*/
|
|
|
|
|
|
|
|
void audio_enter_stream()
|
|
|
|
{
|
|
|
|
while (send_data(am_thread, MSG_ENTER_STREAM, NULL, 0) == B_INTERRUPTED) ;
|
|
|
|
while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Last source removed, stop audio stream
|
|
|
|
*/
|
|
|
|
|
|
|
|
void audio_exit_stream()
|
|
|
|
{
|
|
|
|
while (send_data(am_thread, MSG_EXIT_STREAM, NULL, 0) == B_INTERRUPTED) ;
|
|
|
|
while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Streaming function
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer
|
|
|
|
|
|
|
|
static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format)
|
|
|
|
{
|
|
|
|
// Check if new buffer is available
|
|
|
|
if (acquire_sem_etc(audio_irq_done_sem, 1, B_TIMEOUT, 0) == B_NO_ERROR) {
|
|
|
|
|
|
|
|
// Get size of audio data
|
|
|
|
D(bug("stream: new buffer present\n"));
|
|
|
|
uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo);
|
|
|
|
if (apple_stream_info) {
|
|
|
|
size_t work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels;
|
|
|
|
D(bug("stream: size %d, work_size %d\n", size, work_size));
|
|
|
|
if (work_size > size)
|
|
|
|
work_size = size;
|
|
|
|
|
|
|
|
if (format.format != media_raw_audio_format::B_AUDIO_SHORT) {
|
|
|
|
D(bug("Wrong audio format %04x\n", format.format));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Place data into Media Kit buffer
|
1999-11-03 10:56:43 +00:00
|
|
|
Mac2Host_memcpy(buf, ReadMacInt32(apple_stream_info + scd_buffer), work_size);
|
1999-10-03 14:16:26 +00:00
|
|
|
if (work_size != size)
|
|
|
|
memset((uint8 *)buf + work_size, 0, size - work_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else
|
|
|
|
memset(buf, 0, size);
|
|
|
|
|
|
|
|
// Trigger audio interrupt to get new buffer
|
|
|
|
if (AudioStatus.num_sources) {
|
|
|
|
D(bug("stream: triggering irq\n"));
|
|
|
|
SetInterruptFlag(INTFLAG_AUDIO);
|
|
|
|
TriggerInterrupt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MacOS audio interrupt, read next data block
|
|
|
|
*/
|
|
|
|
|
|
|
|
void AudioInterrupt(void)
|
|
|
|
{
|
|
|
|
D(bug("AudioInterrupt\n"));
|
|
|
|
|
|
|
|
// Get data from apple mixer
|
|
|
|
if (AudioStatus.mixer) {
|
|
|
|
M68kRegisters r;
|
|
|
|
r.a[0] = audio_data + adatStreamInfo;
|
|
|
|
r.a[1] = AudioStatus.mixer;
|
|
|
|
Execute68k(audio_data + adatGetSourceData, &r);
|
|
|
|
D(bug(" GetSourceData() returns %08lx\n", r.d[0]));
|
|
|
|
} else
|
|
|
|
WriteMacInt32(audio_data + adatStreamInfo, 0);
|
|
|
|
|
|
|
|
// Signal stream function
|
|
|
|
release_sem(audio_irq_done_sem);
|
|
|
|
D(bug("AudioInterrupt done\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set sampling parameters
|
|
|
|
* "index" is an index into the audio_sample_rates[] etc. arrays
|
|
|
|
* It is guaranteed that AudioStatus.num_sources == 0
|
|
|
|
*/
|
|
|
|
|
|
|
|
void audio_set_sample_rate(int index)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_set_sample_size(int index)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_set_channels(int index)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get/set audio info
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool audio_get_main_mute(void)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 audio_get_main_volume(void)
|
|
|
|
{
|
|
|
|
if (audio_open) {
|
|
|
|
while (send_data(am_thread, MSG_GET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
|
|
|
|
while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
|
|
|
|
return int(am_volume * 256.0) * 0x00010001;
|
|
|
|
} else
|
|
|
|
return 0x01000100;
|
|
|
|
}
|
|
|
|
|
1999-10-20 15:14:00 +00:00
|
|
|
bool audio_get_speaker_mute(void)
|
1999-10-03 14:16:26 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
1999-10-20 15:14:00 +00:00
|
|
|
uint32 audio_get_speaker_volume(void)
|
1999-10-03 14:16:26 +00:00
|
|
|
{
|
|
|
|
return 0x01000100;
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_set_main_mute(bool mute)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_set_main_volume(uint32 vol)
|
|
|
|
{
|
|
|
|
if (audio_open) {
|
|
|
|
am_volume = float((vol >> 16) + (vol & 0xffff)) / 512.0;
|
|
|
|
while (send_data(am_thread, MSG_SET_VOLUME, NULL, 0) == B_INTERRUPTED) ;
|
|
|
|
while (acquire_sem(am_done_sem) == B_INTERRUPTED) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-20 15:14:00 +00:00
|
|
|
void audio_set_speaker_mute(bool mute)
|
1999-10-03 14:16:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1999-10-20 15:14:00 +00:00
|
|
|
void audio_set_speaker_volume(uint32 vol)
|
1999-10-03 14:16:26 +00:00
|
|
|
{
|
|
|
|
}
|