ALuint SoundManager::load_file_into_buffer(const std::string& filename) { // open sound file std::auto_ptr<SoundFile> file (load_sound_file(filename)); ALenum format = get_sample_format(file.get()); ALuint buffer; alGenBuffers(1, &buffer); check_al_error("Couldn't create audio buffer: "); char* samples = new char[file->size]; try { file->read(samples, file->size); alBufferData(buffer, format, samples, static_cast<ALsizei> (file->size), static_cast<ALsizei> (file->rate)); check_al_error("Couldn't fill audio buffer: "); } catch(...) { delete[] samples; throw; } delete[] samples; return buffer; }
void fs_emu_init_audio_stream(int stream, fs_emu_audio_stream_options *options) { fs_log("initializing audio stream %d\n", stream); audio_stream *s = g_malloc0(sizeof(audio_stream)); s->buffer_size = options->buffer_size; s->frequency = options->frequency; s->num_buffers = MAX_BUFFERS; s->min_buffers = options->min_buffers; fs_log("frequency: %d, buffers: %d buffer size: %d bytes\n", s->frequency, s->num_buffers, s->buffer_size); s->mutex = g_mutex_new(); s->queue = g_queue_new(); alGenSources(1, &s->source); check_al_error("alGenSources"); for (int i = 0; i < s->num_buffers; i++) { ALuint buffer; alGenBuffers(1, &buffer); check_al_error("alGenBuffers"); g_queue_push_tail(s->queue, GUINT_TO_POINTER(buffer)); } s->buffers_queued = 0; // FIXME: configure elsewhere if (stream == 0) { s->fill_target = 8 * 1024; } else { s->fill_target = 0; } s->pid_last_error = 0; s->pid_last_last_error = 0; s->pid_last_time = 0; s->pid_last_last_time = 0; g_streams[stream] = s; }
static void unqueue_old_buffers(int stream) { audio_stream *s = g_streams[stream]; ALint old_buffers = 0; fs_mutex_lock(s->mutex); // locking here because unqueue_old_buffers can be run called from // both the video thread and the emulation thread (consider changing this, // perhaps even have a separate thread for periodically unqueuing). alGetSourcei(s->source, AL_BUFFERS_PROCESSED, &old_buffers); check_al_error("alGetSourcei (AL_BUFFERS_PROCESSED)"); if (old_buffers > 0) { ALuint buffers[MAX_BUFFERS]; old_buffers = MIN(old_buffers, MAX_BUFFERS); alSourceUnqueueBuffers(s->source, old_buffers, buffers); if (check_al_error("alSourceUnqueueBuffers") != AL_NO_ERROR) { fs_log("while trying to unqueue %d buffers\n"); } for (int i = 0; i < old_buffers; i++) { g_queue_push_tail(s->queue, FS_UINT_TO_POINTER(buffers[i])); } s->buffers_queued -= old_buffers; } fs_mutex_unlock(s->mutex); }
void loop(const OpenAlSound& sound) { alSourcei(_source, AL_LOOPING, AL_TRUE); check_al_error("alSourcei"); alSourcei(_source, AL_BUFFER, sound.buffer()); check_al_error("alSourcei"); alSourcePlay(_source); check_al_error("alSourcePlay"); }
OpenAlChannel(OpenAlSoundDriver& driver): _driver(driver) { alGenSources(1, &_source); check_al_error("alGenSources"); alSourcef(_source, AL_PITCH, 1.0f); alSourcef(_source, AL_GAIN, 1.0f); check_al_error("alSourcef"); }
system::sound_id system::load_wav(const std::string& filename) { sound_id bad_id = -1; sound_info buffer; ALenum format; ALvoid* data; ALsizei size; ALsizei freq; ALboolean loop; ALuint buf_id = 0; buffer.m_filename = filename; sound_buffers::const_iterator end_it = m_d->m_buffers->end(); for(sound_buffers::const_iterator it = m_d->m_buffers->begin(); it != end_it; ++it) { if(it->second.m_filename == filename) { buf_id = it->first; break; } } if(!buf_id) { alGenBuffers(1, &buffer.m_id); if(!check_al_error()) { return false; } alutLoadWAVFile((ALbyte *)filename.c_str(), &format, &data, &size, &freq, &loop); if (!check_al_error()) { return bad_id; } buffer.m_format = format; buffer.m_rate = freq; alBufferData(buffer.m_id, format, data, size, freq); if (!check_al_error()) { return bad_id; } alutUnloadWAV(format, data, size, freq); if (!check_al_error()) { return bad_id; } m_d->m_buffers->insert(sound_buffers::value_type(buf_id, buffer)); } else { buffer = (*m_d->m_buffers)[buf_id]; } return buffer.m_id; }
int fs_emu_queue_audio_buffer(int stream, int16_t* data, int size) { if (g_fs_emu_benchmarking) { // no audio output while benchmarking return 0; } //fs_log("fs_emu_queue_audio_buffer stream %d\n", stream); audio_stream *s = g_streams[stream]; ALuint buffer = 0; g_mutex_lock(s->mutex); //while (1) { buffer = GPOINTER_TO_UINT(g_queue_pop_head(s->queue)); if (!buffer) { fs_log("no audio buffer available - dropping data\n"); g_mutex_unlock(s->mutex); return 0; } s->buffers_queued += 1; // create a local copy while we have the lock int buffers_queued = s->buffers_queued; g_mutex_unlock(s->mutex); alBufferData(buffer, AL_FORMAT_STEREO16, data, size, s->frequency); check_al_error("alBufferData"); alSourceQueueBuffers(s->source, 1, &buffer); check_al_error("alSourceQueueBuffers"); ALint state; alGetSourcei(s->source, AL_SOURCE_STATE, &state); check_al_error("alGetSourcei (AL_SOURCE_STATE)"); if (state != AL_PLAYING) { // we have had a buffer underrun - we now wait until we have queued // some buffers if (buffers_queued < s->min_buffers) { // want more buffers } else { fs_log("restarting audio stream %d (buffer underrun)\n", stream); alSourcePlay(s->source); check_al_error("alSourcePlay"); } } double want_volume = g_volume * 0.9; if (want_volume != s->source_volume_current) { s->source_volume_current = want_volume; alSourcef(s->source, AL_GAIN, want_volume); } unqueue_old_buffers(stream); return buffer; }
SoundManager::SoundManager() : device(0), context(0), sound_enabled(false), music_source(0), music_enabled(true) { try { device = alcOpenDevice(0); if(device == 0) { print_openal_version(); throw std::runtime_error("Couldn't open audio device."); } int attributes[] = { 0 }; context = alcCreateContext(device, attributes); check_alc_error("Couldn't create audio context: "); alcMakeContextCurrent(context); check_alc_error("Couldn't select audio context: "); check_al_error("Audio error after init: "); sound_enabled = true; } catch(std::exception& e) { device = 0; context = 0; log_warning << "Couldn't initialize audio device:" << e.what() << std::endl; print_openal_version(); throw e; } }
static void set_paused(int stream, bool paused) { if (paused) { fs_log("fs_emu_audio_resume_stream %d\n", stream); audio_stream *s = g_streams[stream]; alSourcePause(s->source); g_fs_emu_audio_stream_playing[stream] = 0; check_al_error("alSourcePlay"); } else { fs_log("fs_emu_audio_resume_stream %d\n", stream); audio_stream *s = g_streams[stream]; alSourcePlay(s->source); g_fs_emu_audio_stream_playing[stream] = 1; check_al_error("alSourcePlay"); } }
ALuint SoundManager::load_file_into_buffer(SoundFile& file) { ALenum format = get_sample_format(file); ALuint buffer; alGenBuffers(1, &buffer); check_al_error("Couldn't create audio buffer: "); std::unique_ptr<char[]> samples(new char[file.size]); file.read(samples.get(), file.size); alBufferData(buffer, format, samples.get(), static_cast<ALsizei>(file.size), static_cast<ALsizei>(file.rate)); check_al_error("Couldn't fill audio buffer: "); return buffer; }
void buffer(const AudioFile& audio_file) { Bytes data; ALenum format; ALsizei frequency; audio_file.convert(&data, &format, &frequency); alBufferData(_buffer, format, data.data(), data.size(), frequency); check_al_error("alBufferData"); }
static void fs_emu_init_audio_stream(int stream, fs_emu_audio_stream_options *options) { audio_stream *s = g_malloc0(sizeof(audio_stream)); s->buffer_size = options->buffer_size; s->frequency = options->frequency; s->num_buffers = MAX_BUFFERS; s->min_buffers = options->min_buffers; fs_log("AUDIO: Stream %d, frequency: %d, buffers: %d buffer " "size: %d bytes\n", stream, s->frequency, s->num_buffers, s->buffer_size); s->mutex = fs_mutex_create(); s->queue = g_queue_new(); s->source_volume_current = 1.0; s->buffers_queued = 0; s->pid_last_error = 0; s->pid_last_last_error = 0; s->pid_last_time = 0; s->pid_last_last_time = 0; alGenSources(1, &s->source); //alSourcei (s->source, AL_SOURCE_RELATIVE, AL_TRUE); //alSource3f(s->source, AL_POSITION, 0.0, 0.0, -1.0); //alSourcef (s->source, AL_ROLLOFF_FACTOR, 0.0); // AL_DIRECT_CHANNELS_SOFT alSourcei(s->source, 0x1033, AL_TRUE); check_al_error("alGenSources"); for (int i = 0; i < s->num_buffers; i++) { ALuint buffer; alGenBuffers(1, &buffer); check_al_error("alGenBuffers"); g_queue_push_tail(s->queue, FS_UINT_TO_POINTER(buffer)); } if (stream == 0) { s->fill_target = g_default_fill_target; } else { s->fill_target = 0; } g_streams[stream] = s; }
ALuint SoundManager::load_file_into_buffer(SoundFile* file) { ALenum format = get_sample_format(file); ALuint buffer; alGenBuffers(1, &buffer); check_al_error("Couldn't create audio buffer: "); char* samples = new char[file->size]; try { file->read(samples, file->size); alBufferData(buffer, format, samples, static_cast<ALsizei> (file->size), static_cast<ALsizei> (file->rate)); check_al_error("Couldn't fill audio buffer: "); } catch(...) { delete[] samples; throw; } delete[] samples; return buffer; }
static void pid_controller_step(int stream, int time_ms) { audio_stream *s = g_streams[stream]; if (s->fill_target == 0) { return; } if (s->pid_last_last_time == 0) { s->pid_last_time = time_ms; s->pid_last_last_time = time_ms; } int dt = time_ms - s->pid_last_last_time; int error = s->fill_target - s->fill_stat_buffer_avg; //static double last_error = 0.0; //if (s->pid_last_error == 0.0) { // s->pid_last_error = error; //} //s->pid_integral = s->pid_integral + (error * dt); //s->pid_integral = s->err_stat_buffer_sum; double derivative; if (dt > 0) { derivative = (s->pid_last_last_error - error) / dt; } else { derivative = 0; } double output = KP * error + KI * s->err_stat_buffer_sum + KD * derivative; s->pid_last_last_error = s->pid_last_error; s->pid_last_last_time = s->pid_last_time; s->pid_last_error = error; s->pid_last_time = time_ms; s->pitch = g_default_audio_pitch - output; s->pitch = MAX(0.5, MIN(2.0, s->pitch)); #if 0 static int count = 0; if (++count % 25 == 0) { printf("pitch: %0.3f (output %0.6f err %d err sum %d)\n", s->pitch, output, error, s->err_stat_buffer_sum); } #endif alSourcef(s->source, AL_PITCH, (ALfloat) s->pitch); check_al_error("alSourcef (AL_PITCH)"); }
void fs_emu_audio_init() { fs_log("fs_emu_audio_init\n"); // select the "preferred device" g_device = alcOpenDevice(NULL); if (!g_device) { fs_log("WARNING: could not open OpenAL device\n"); } #if 0 // FIXME: enable later ALCint attributes[3] = { ALC_FREQUENCY, 48000, 0 }; fs_log("openal: trying 48000\n"); g_context = alcCreateContext(g_device, attributes); if (g_context) { g_audio_out_frequency = 48000; } else { //check_al_error("alcCreateContext"); fs_log("openal: trying without frequency specified\n"); } #endif if (!g_context) { g_context = alcCreateContext(g_device, NULL); g_audio_out_frequency = 44100; } if (g_context) { fs_log("openal: created context\n"); alcMakeContextCurrent(g_context); check_al_error("alcMakeContextCurrent"); fs_log("openal: made context current\n"); } else { fs_log("ERROR: no OpenAL context\n"); //check_al_error("alcCreateContext"); } // FIXME: }
SoundManager::SoundManager() : device(0), context(0), sound_enabled(false), buffers(), sources(), update_list(), music_source(0), music_enabled(false), current_music() { try { device = alcOpenDevice(0); if (device == NULL) { throw std::runtime_error("Couldn't open audio device."); } int attributes[] = { 0 }; context = alcCreateContext(device, attributes); check_alc_error("Couldn't create audio context: "); alcMakeContextCurrent(context); check_alc_error("Couldn't select audio context: "); check_al_error("Audio error after init: "); sound_enabled = true; music_enabled = true; } catch(std::exception& e) { if(context != NULL) { alcDestroyContext(context); context = NULL; } if(device != NULL) { alcCloseDevice(device); device = NULL; } log_warning << "Couldn't initialize audio device: " << e.what() << std::endl; print_openal_version(); } }
void fs_emu_audio_openal_init(void) { fs_log("fs_emu_audio_openal_init\n"); register_functions(); // select the "preferred device" g_device = alcOpenDevice(NULL); if (g_device) { fs_log("[OPENAL] Opened device: %s\n", alcGetString(g_device, ALC_DEVICE_SPECIFIER)); } else { fs_log("[OPENAL] NULL from alcOpenDevice\n"); ALenum error_code = alGetError(); fs_log("[OPENAL] Error code %d\n", error_code); if (alGetString(error_code)) { fs_log("[OPENAL] %s\n", alGetString(error_code)); } fs_emu_warning("OPENAL: Could not open audio device"); } if (!g_device) { return; } log_openal_info(); log_openal_devices(); int frequencies[] = { 48000, 44100, 0 }; if (fs_config_get_int("audio_frequency") != FS_CONFIG_NONE) { frequencies[0] = fs_config_get_int("audio_frequency"); } for (int i = 0; frequencies[i]; i++) { int frequency = frequencies[i]; fs_log("OPENAL: trying frequency %d\n", frequency); ALCint attributes[] = { ALC_MONO_SOURCES, 0, ALC_STEREO_SOURCES, 2, ALC_FREQUENCY, frequency, 0 }; g_context = alcCreateContext(g_device, attributes); if (g_context) { g_audio_out_frequency = frequency; break; } } if (g_context) { fs_log("OPENAL: created context\n"); alcMakeContextCurrent(g_context); check_al_error("alcMakeContextCurrent"); fs_log("OPENAL: made context current\n"); } else { fs_emu_warning("OpenAL: no context created\n"); //check_al_error("alcCreateContext"); } int stereo_sources; alcGetIntegerv(g_device, ALC_STEREO_SOURCES, 1, &stereo_sources); fs_log("openal: number of stereo sources is %d\n", stereo_sources); // FIXME: configure elsewhere int abt = fs_config_get_int_clamped("audio_buffer_target_size", 1, 100); if (abt == FS_CONFIG_NONE) { if (fs_config_get_int("audio_buffer_target_bytes") != FS_CONFIG_NONE) { fs_emu_warning("Use audio_buffer_target_size instead\n"); } abt = 40; #if 0 if (abt == FS_CONFIG_NONE) { abt = 40; } else { abt = (int) (abt / 1000.0 * (options->frequency * 2 * 2)); } #endif } fs_log("AUDIO: Buffer target size (ms) = %d\n", abt); //abt = (int) (abt / 1000.0 * (options->frequency * 2 * 2)); // fs_log("AUDIO: Buffer target size (bytes) = %d\n", abt); /* Specifying fill target in microseconds */ g_default_fill_target = abt * 1000; }
static ALuint generate_buffer() { ALuint buffer; alGenBuffers(1, &buffer); check_al_error("alGenBuffers"); return buffer; }
static int queue_buffer(int stream, int16_t* data, int size) { if (g_fs_emu_benchmark_mode) { /* no audio output while benchmarking */ return 0; } if (g_fs_emu_benchmarking) { /* no audio output while benchmarking */ return 0; } //fs_log("fs_emu_queue_audio_buffer stream %d size %d\n", stream, size); audio_stream *s = g_streams[stream]; ALuint buffer = 0; fs_mutex_lock(s->mutex); //while (1) { buffer = FS_POINTER_TO_UINT(g_queue_pop_head(s->queue)); if (!buffer) { fs_log("no audio buffer available - dropping data\n"); fs_mutex_unlock(s->mutex); return 0; } s->buffers_queued += 1; // create a local copy while we have the lock //int buffers_queued = s->buffers_queued; fs_mutex_unlock(s->mutex); #if 0 /* for debugging, clear one of the stereo channels */ int16_t *d = data; for (int i = 0; i < size / 4; i++) { d++; *d = 0; d++; } #endif alBufferData(buffer, AL_FORMAT_STEREO16, data, size, s->frequency); check_al_error("alBufferData"); alSourceQueueBuffers(s->source, 1, &buffer); check_al_error("alSourceQueueBuffers"); ALint state; alGetSourcei(s->source, AL_SOURCE_STATE, &state); check_al_error("alGetSourcei (AL_SOURCE_STATE)"); if (state != AL_PLAYING) { g_fs_emu_audio_buffer_underrun_time = fs_get_monotonic_time(); g_fs_emu_audio_buffer_underruns += 1; // we have had a buffer underrun - we now wait until we have queued // some buffers //if (buffers_queued < s->min_buffers) { // // want more buffers //} //else { fs_log("restarting audio stream %d (buffer underrun)\n", stream); alSourcePlay(s->source); g_fs_emu_audio_stream_playing[stream] = 1; check_al_error("alSourcePlay"); //} } double want_volume = g_fs_emu_audio_want_volume[stream] * 0.9; if (want_volume != s->source_volume_current) { s->source_volume_current = want_volume; alSourcef(s->source, AL_GAIN, want_volume); } unqueue_old_buffers(stream); return buffer; }
virtual void amp(uint8_t volume) { alSourcef(_source, AL_GAIN, volume / 256.0f); check_al_error("alSourcef"); }
virtual void quiet() { alSourceStop(_source); check_al_error("alSourceStop"); }