/***********************************************************/ // 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 #include #include 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; }