uae-wii/src/sd-beos/sound.cpp
2009-05-05 15:36:48 +00:00

297 lines
7.6 KiB
C++
Raw Permalink Blame History

/***********************************************************/
// BeUAE - The Be Un*x Amiga Emulator
//
// BeOS port sound routines
// Using R4 BSoundPlayer class
//
// (c) 2004-2007 Richard Drummond
// (c) 2000-2001 Axel D<>fler
// (c) 1999 Be/R4 Sound - Raphael Moll
// (c) 1998-1999 David Sowsy
//
// History:
//
// -RM/050999 : removed debug code, code cleanup, etc.
// -DS/051399 : adapted code to build under 0.8.8.
// New Media Kit woes ensued.
// -DS/06xx99 : adapted code to work with the new Game Kit.
// -AD/121300 : supports now different frequencies, bitsrates, and stereo modes
// -AD/121500 : blocks now correctly to synchronize UAE
// -RD/012804 : updated for UAE 0.8.23
/***********************************************************/
extern "C" {
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "sounddep/sound.h"
}
#include <be/media/MediaRoster.h>
#include <be/media/SoundPlayer.h>
#include <be/media/MediaDefs.h>
extern "C" {
void finish_sound_buffer (void);
void update_sound (int freq);
int setup_sound (void);
void close_sound (void);
int init_sound (void);
void pause_sound (void);
void resume_sound (void);
void reset_sound (void);
void sound_volume (int dir);
}
uae_u16 *sndbuffer;
uae_u16 *sndbufpt;
int sndbufsize;
BSoundPlayer *gSoundPlayer;
static int32 gSoundBufferSize;
static uae_u16 *gDoubleBufferRead;
static uae_u16 *gDoubleBufferWrite;
static uae_u16 *gLastBuffer;
static int32 gBufferReadPos;
static uae_u16 *buffer = NULL;
static bool sound_ready = false;
static sem_id sound_sync_sem;
void stream_func8 (void *user, void *buffer, size_t size, const media_raw_audio_format &format);
void stream_func16 (void *user, void *buffer, size_t size, const media_raw_audio_format &format);
int init_sound (void)
{
if (gSoundPlayer != NULL)
return 0;
media_raw_audio_format audioFormat;
gSoundBufferSize = currprefs.sound_freq * currprefs.sound_latency * (currprefs.sound_bits / 8) *
(currprefs.sound_stereo ? 2 : 1) / 1000;
gSoundBufferSize = (gSoundBufferSize + 7) & ~8;
audioFormat.frame_rate = currprefs.sound_freq;
audioFormat.channel_count = currprefs.sound_stereo ? 2 : 1;
audioFormat.format = media_raw_audio_format::B_AUDIO_FLOAT;
audioFormat.byte_order = B_MEDIA_HOST_ENDIAN;
audioFormat.buffer_size = gSoundBufferSize * sizeof(float);
gSoundPlayer = new BSoundPlayer (&audioFormat, "UAE SoundPlayer",
currprefs.sound_bits == 8 ? stream_func8 : stream_func16);
sound_ready = (gSoundPlayer != NULL);
if (!currprefs.produce_sound)
return 3;
sound_sync_sem = create_sem (0, "UAE Sound Sync Semaphore");
gBufferReadPos = 0;
gDoubleBufferWrite = new uae_u16[2 * gSoundBufferSize];
gDoubleBufferRead = gDoubleBufferWrite + gSoundBufferSize;
buffer = gDoubleBufferWrite;
memset (buffer, 0, 4 * gSoundBufferSize);
sndbufpt = sndbuffer = buffer;
if (currprefs.sound_bits == 8) {
sndbufsize = sizeof (uae_u8) * gSoundBufferSize;
sample_handler = currprefs.sound_stereo ? sample8s_handler : sample8_handler;
init_sound_table8 ();
} else {
sndbufsize = sizeof (uae_u16) * gSoundBufferSize;
if (currprefs.sound_stereo)
sample_handler = sample16s_handler;
else
sample_handler = sample16_handler;
init_sound_table16 ();
}
sound_available = 1;
obtainedfreq = currprefs.sound_freq;
write_log ("BeOS sound driver found and configured for %d bits at %d Hz, buffer is %d samples\n",
currprefs.sound_bits, currprefs.sound_freq, gSoundBufferSize);
if (gSoundPlayer) {
gSoundPlayer->Start ();
gSoundPlayer->SetHasData (true);
return 1;
}
return 0;
}
int setup_sound (void)
{
status_t err;
BMediaRoster *gMediaRoster;
media_node *outNode;
outNode = new media_node;
gMediaRoster = BMediaRoster::Roster (&err);
if (gMediaRoster && err == B_OK)
err = gMediaRoster->GetAudioOutput (outNode);
if ((!gMediaRoster) || (err != B_OK)) {
write_log ("NO MEDIA ROSTER! The media server "
"appears to be dead.\n"
"\t-- roster %p -- error %08lx (%ld)\n",
gMediaRoster, err, err);
sound_available = 0;
} else
sound_available = 1;
return sound_available;
}
void close_sound (void)
{
if (sound_ready) {
if (gSoundPlayer) {
gSoundPlayer->Stop();
delete gSoundPlayer;
gSoundPlayer = NULL;
}
sound_ready = false;
}
delete_sem(sound_sync_sem);
if (gDoubleBufferRead < gDoubleBufferWrite)
delete[] gDoubleBufferRead;
else
delete[] gDoubleBufferWrite;
gDoubleBufferRead = gDoubleBufferWrite = NULL;
}
void finish_sound_buffer (void)
{
if (sound_ready && acquire_sem (sound_sync_sem) == B_OK) {
uae_u16 *p = gDoubleBufferRead; // swap buffers
gDoubleBufferRead = gDoubleBufferWrite;
buffer = gDoubleBufferWrite = p;
}
sndbufpt = sndbuffer = buffer;
}
void stream_func16 (void *user, void *buffer, size_t size,const media_raw_audio_format &format)
{
uae_u16 *buf;
int32 max_read_sample, avail_sample;
// since the BSoundPlayer supports only B_AUDIO_FLOAT, it's
// very unlikely that this will ever happen:
// if (format.format != media_raw_audio_format::B_AUDIO_FLOAT) return;
float *dest = (float *)buffer;
int32 dest_sample = (int32)(size / sizeof (float));
float *enddest = dest + dest_sample;
max_read_sample = gSoundBufferSize;
if (dest_sample < max_read_sample)
max_read_sample = dest_sample;
buf = gDoubleBufferRead + gBufferReadPos;
avail_sample = gSoundBufferSize - gBufferReadPos;
if (avail_sample < max_read_sample)
max_read_sample = avail_sample;
if (max_read_sample)
gBufferReadPos += max_read_sample;
const float ratio = 1.f / 32768.f;
while(max_read_sample--) // copy the buffer to the stream
{
int16 a = (int16)(*(buf++));
*(dest++) = ((float)a) * ratio;
}
// the buffer is no longer needed, so lets release it.
// if UAE is not fast enough to swap the buffers during play time, the same
// buffer will be played again
if (gBufferReadPos == gSoundBufferSize) {
gBufferReadPos = 0;
if (gLastBuffer != gDoubleBufferRead) {
gLastBuffer = gDoubleBufferRead;
release_sem (sound_sync_sem);
}
}
while (dest < enddest)
*(dest++) = 0.f;
}
void stream_func8 (void *user, void *buffer, size_t size,const media_raw_audio_format &format)
{
int32 max_read_sample, avail_sample;
uae_u8 *buf;
float *dest = (float *)buffer;
int32 dest_sample = (int32)(size / sizeof (float));
float *enddest = dest + dest_sample;
max_read_sample = gSoundBufferSize;
if (dest_sample < max_read_sample)
max_read_sample = dest_sample;
buf = (uae_u8 *)gDoubleBufferRead + gBufferReadPos;
avail_sample = gSoundBufferSize - gBufferReadPos;
if (avail_sample < max_read_sample)
max_read_sample = avail_sample;
if (max_read_sample)
gBufferReadPos += max_read_sample;
const float ratio = 1.f / 128.f;
while (max_read_sample--)
*(dest++) = ((float)*(buf++) - 128) * ratio;
if (gBufferReadPos == gSoundBufferSize) {
gBufferReadPos = 0;
if (gLastBuffer != gDoubleBufferRead) {
gLastBuffer = gDoubleBufferRead;
release_sem (sound_sync_sem);
}
}
while (dest < enddest)
*(dest++) = 0.f;
}
void pause_sound (void)
{
close_sound ();
return;
}
void resume_sound (void)
{
init_sound ();
return;
}
void reset_sound (void)
{
}
void sound_volume (int dir)
{
}
/*
* Handle audio specific cfgfile options
*/
void audio_default_options (struct uae_prefs *p)
{
}
void audio_save_options (FILE *f, const struct uae_prefs *p)
{
}
int audio_parse_option (struct uae_prefs *p, const char *option, const char *value)
{
return 0;
}