virtualx-engine/servers/audio/audio_server_sw.cpp
Rémi Verschelde d8223ffa75 Welcome in 2017, dear changelog reader!
That year should bring the long-awaited OpenGL ES 3.0 compatible renderer
with state-of-the-art rendering techniques tuned to work as low as middle
end handheld devices - without compromising with the possibilities given
for higher end desktop games of course. Great times ahead for the Godot
community and the gamers that will play our games!

(cherry picked from commit c7bc44d5ad)
2017-01-12 19:15:30 +01:00

1028 lines
25 KiB
C++

/*************************************************************************/
/* audio_server_sw.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "audio_server_sw.h"
#include "globals.h"
#include "os/os.h"
struct _AudioDriverLock {
_AudioDriverLock() { if (AudioDriverSW::get_singleton()) AudioDriverSW::get_singleton()->lock(); }
~_AudioDriverLock() { if (AudioDriverSW::get_singleton()) AudioDriverSW::get_singleton()->unlock(); }
};
#define AUDIO_LOCK _AudioDriverLock _adlock;
AudioMixer *AudioServerSW::get_mixer() {
return mixer;
}
/* CALLBACKS */
void AudioServerSW::audio_mixer_chunk_callback(int p_frames) {
/*
for(List<Stream*>::Element *E=event_streams.front();E;E=E->next()) {
if (E->get()->active)
E->get()->audio_stream->mix(NULL,p_frames);
}
*/
}
void AudioServerSW::_mixer_callback(void *p_udata) {
AudioServerSW *self = (AudioServerSW*)p_udata;
for(List<Stream*>::Element *E=self->active_audio_streams.front();E;E=E->next()) {
if (!E->get()->active)
continue;
EventStream *es=E->get()->event_stream;
if (!es)
continue;
es->update(self->mixer_step_usecs);
}
}
void AudioServerSW::driver_process_chunk(int p_frames,int32_t *p_buffer) {
int samples=p_frames*internal_buffer_channels;
for(int i=0;i<samples;i++) {
internal_buffer[i]=0;
}
while(voice_rb.commands_left()) {
VoiceRBSW::Command cmd = voice_rb.pop_command();
if (cmd.type==VoiceRBSW::Command::CMD_CHANGE_ALL_FX_VOLUMES) {
SelfList<Voice>*al = active_list.first();
while(al) {
Voice *v=al->self();
if (v->channel!=AudioMixer::INVALID_CHANNEL) {
mixer->channel_set_volume(v->channel,v->volume*fx_volume_scale);
}
al=al->next();
}
continue;
}
if (!voice_owner.owns(cmd.voice))
continue;
Voice *v = voice_owner.get(cmd.voice);
switch(cmd.type) {
case VoiceRBSW::Command::CMD_NONE: {
} break;
case VoiceRBSW::Command::CMD_PLAY: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_free(v->channel);
RID sample = cmd.play.sample;
if (!sample_manager->is_sample(sample))
continue;
v->channel=mixer->channel_alloc(sample);
v->volume=1.0;
mixer->channel_set_volume(v->channel,fx_volume_scale);
if (v->channel==AudioMixer::INVALID_CHANNEL) {
#ifdef AUDIO_DEBUG
WARN_PRINT("AUDIO: all channels used, failed to allocate voice");
#endif
v->active=false;
break; // no voices left?
}
v->active=true; // this kind of ensures it works
if (!v->active_item.in_list())
active_list.add(&v->active_item);
} break;
case VoiceRBSW::Command::CMD_STOP: {
if (v->channel!=AudioMixer::INVALID_CHANNEL) {
mixer->channel_free(v->channel);
if (v->active_item.in_list()) {
active_list.remove(&v->active_item);
}
}
v->active=false;
} break;
case VoiceRBSW::Command::CMD_SET_VOLUME: {
if (v->channel!=AudioMixer::INVALID_CHANNEL) {
v->volume=cmd.volume.volume;
mixer->channel_set_volume(v->channel,cmd.volume.volume*fx_volume_scale);
}
} break;
case VoiceRBSW::Command::CMD_SET_PAN: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_pan(v->channel,cmd.pan.pan,cmd.pan.depth,cmd.pan.height);
} break;
case VoiceRBSW::Command::CMD_SET_FILTER: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_filter(v->channel,(AudioMixer::FilterType)cmd.filter.type,cmd.filter.cutoff,cmd.filter.resonance,cmd.filter.gain);
} break;
case VoiceRBSW::Command::CMD_SET_CHORUS: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_chorus(v->channel,cmd.chorus.send);
} break;
case VoiceRBSW::Command::CMD_SET_REVERB: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_reverb(v->channel,(AudioMixer::ReverbRoomType)cmd.reverb.room,cmd.reverb.send);
} break;
case VoiceRBSW::Command::CMD_SET_MIX_RATE: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_mix_rate(v->channel,cmd.mix_rate.mix_rate);
} break;
case VoiceRBSW::Command::CMD_SET_POSITIONAL: {
if (v->channel!=AudioMixer::INVALID_CHANNEL)
mixer->channel_set_positional(v->channel,cmd.positional.positional);
} break;
default: {}
}
}
mixer->mix(internal_buffer,p_frames);
//uint64_t stepsize=mixer->get_step_usecs();
for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) {
ERR_CONTINUE(!E->get()->active); // bug?
AudioStream *as=E->get()->audio_stream;
if (!as)
continue;
int channels=as->get_channel_count();
if (channels==0)
continue; // does not want mix
if (!as->mix(stream_buffer,p_frames))
continue; //nothing was mixed!!
int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS);
#define STRSCALE(m_val) (((m_val>>STREAM_SCALE_BITS)*stream_vol_scale)>>8)
switch(internal_buffer_channels) {
case 2: {
switch(channels) {
case 1: {
for(int i=0;i<p_frames;i++) {
internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]);
internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]);
}
} break;
case 2: {
for(int i=0;i<p_frames*2;i++) {
internal_buffer[i]+=STRSCALE(stream_buffer[i]);
}
} break;
case 4: {
for(int i=0;i<p_frames;i++) {
internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1);
internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1);
}
} break;
} break;
} break;
case 4: {
switch(channels) {
case 1: {
for(int i=0;i<p_frames;i++) {
internal_buffer[(i<<2)+0]+=STRSCALE(stream_buffer[i]);
internal_buffer[(i<<2)+1]+=STRSCALE(stream_buffer[i]);
internal_buffer[(i<<2)+2]+=STRSCALE(stream_buffer[i]);
internal_buffer[(i<<2)+3]+=STRSCALE(stream_buffer[i]);
}
} break;
case 2: {
for(int i=0;i<p_frames*2;i++) {
internal_buffer[(i<<2)+0]+=STRSCALE(stream_buffer[(i<<1)+0]);
internal_buffer[(i<<2)+1]+=STRSCALE(stream_buffer[(i<<1)+1]);
internal_buffer[(i<<2)+2]+=STRSCALE(stream_buffer[(i<<1)+0]);
internal_buffer[(i<<2)+3]+=STRSCALE(stream_buffer[(i<<1)+1]);
}
} break;
case 4: {
for(int i=0;i<p_frames*4;i++) {
internal_buffer[i]+=STRSCALE(stream_buffer[i]);
}
} break;
} break;
} break;
case 6: {
} break;
}
#undef STRSCALE
}
SelfList<Voice> *activeE=active_list.first();
while(activeE) {
SelfList<Voice> *activeN=activeE->next();
if (activeE->self()->channel==AudioMixer::INVALID_CHANNEL || !mixer->channel_is_valid(activeE->self()->channel)) {
active_list.remove(activeE);
activeE->self()->active=false;
}
activeE=activeN;
}
uint32_t peak=0;
for(int i=0;i<samples;i++) {
//clamp to (1<<24) using branchless code
int32_t in = internal_buffer[i];
#ifdef DEBUG_ENABLED
{
int mask = (in >> (32 - 1));
uint32_t p = (in + mask) ^ mask;
if (p>peak)
peak=p;
}
#endif
int32_t lo = -0x800000, hi=0x7FFFFF;
lo-=in;
hi-=in;
in += (lo & ((lo < 0) - 1)) + (hi & ((hi > 0) - 1));
p_buffer[i]=in<<8;
}
if (peak>max_peak)
max_peak=peak;
}
void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) {
_output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate());
//process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
int todo=p_frames;
while(todo) {
int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
driver_process_chunk(tomix,p_buffer);
p_buffer+=tomix;
todo-=tomix;
}
}
/* SAMPLE API */
RID AudioServerSW::sample_create(SampleFormat p_format, bool p_stereo, int p_length) {
AUDIO_LOCK
return sample_manager->sample_create(p_format,p_stereo,p_length);
}
void AudioServerSW::sample_set_description(RID p_sample, const String& p_description) {
AUDIO_LOCK
sample_manager->sample_set_description(p_sample,p_description);
}
String AudioServerSW::sample_get_description(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_description(p_sample);
}
AS::SampleFormat AudioServerSW::sample_get_format(RID p_sample) const {
//AUDIO_LOCK
return sample_manager->sample_get_format(p_sample);
}
bool AudioServerSW::sample_is_stereo(RID p_sample) const {
//AUDIO_LOCK
return sample_manager->sample_is_stereo(p_sample);
}
int AudioServerSW::sample_get_length(RID p_sample) const {
///AUDIO_LOCK
return sample_manager->sample_get_length(p_sample);
}
const void* AudioServerSW::sample_get_data_ptr(RID p_sample) const {
///AUDIO_LOCK
return sample_manager->sample_get_data_ptr(p_sample);
}
void AudioServerSW::sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer) {
AUDIO_LOCK
sample_manager->sample_set_data(p_sample,p_buffer);
}
DVector<uint8_t> AudioServerSW::sample_get_data(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_data(p_sample);
}
void AudioServerSW::sample_set_mix_rate(RID p_sample,int p_rate) {
AUDIO_LOCK
sample_manager->sample_set_mix_rate(p_sample,p_rate);
}
int AudioServerSW::sample_get_mix_rate(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_mix_rate(p_sample);
}
void AudioServerSW::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format) {
AUDIO_LOCK
sample_manager->sample_set_loop_format(p_sample,p_format);
}
AS::SampleLoopFormat AudioServerSW::sample_get_loop_format(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_loop_format(p_sample);
}
void AudioServerSW::sample_set_loop_begin(RID p_sample,int p_pos) {
AUDIO_LOCK
sample_manager->sample_set_loop_begin(p_sample,p_pos);
}
int AudioServerSW::sample_get_loop_begin(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_loop_begin(p_sample);
}
void AudioServerSW::sample_set_loop_end(RID p_sample,int p_pos) {
AUDIO_LOCK
sample_manager->sample_set_loop_end(p_sample,p_pos);
}
int AudioServerSW::sample_get_loop_end(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_loop_end(p_sample);
}
/* VOICE API */
RID AudioServerSW::voice_create() {
Voice * v = memnew( Voice );
v->channel=AudioMixer::INVALID_CHANNEL;
AUDIO_LOCK
return voice_owner.make_rid(v);
}
void AudioServerSW::voice_play(RID p_voice, RID p_sample) {
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND(!v);
v->active=true; // force actvive (will be disabled later i gues..)
//stop old, start new
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_PLAY;
cmd.voice=p_voice;
cmd.play.sample=p_sample;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_volume(RID p_voice, float p_volume) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_VOLUME;
cmd.voice=p_voice;
cmd.volume.volume=p_volume;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_pan(RID p_voice, float p_pan, float p_depth,float p_height) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_PAN;
cmd.voice=p_voice;
cmd.pan.pan=p_pan;
cmd.pan.depth=p_depth;
cmd.pan.height=p_height;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance,float p_gain) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_FILTER;
cmd.voice=p_voice;
cmd.filter.type=p_type;
cmd.filter.cutoff=p_cutoff;
cmd.filter.resonance=p_resonance;
cmd.filter.gain=p_gain;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_chorus(RID p_voice, float p_chorus ) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_CHORUS;
cmd.voice=p_voice;
cmd.chorus.send=p_chorus;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_REVERB;
cmd.voice=p_voice;
cmd.reverb.room=p_room_type;
cmd.reverb.send=p_reverb;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_mix_rate(RID p_voice, int p_mix_rate) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_MIX_RATE;
cmd.voice=p_voice;
cmd.mix_rate.mix_rate=p_mix_rate;
voice_rb.push_command(cmd);
}
void AudioServerSW::voice_set_positional(RID p_voice, bool p_positional) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_POSITIONAL;
cmd.voice=p_voice;
cmd.positional.positional=p_positional;
voice_rb.push_command(cmd);
}
float AudioServerSW::voice_get_volume(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_volume( v->channel );
}
float AudioServerSW::voice_get_pan(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_pan( v->channel );
}
float AudioServerSW::voice_get_pan_depth(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_pan_depth( v->channel );
}
float AudioServerSW::voice_get_pan_height(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_pan_height( v->channel );
}
AS::FilterType AudioServerSW::voice_get_filter_type(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, AS::FILTER_NONE);
return (AS::FilterType)mixer->channel_get_filter_type(v->channel);
}
float AudioServerSW::voice_get_filter_cutoff(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_filter_cutoff( v->channel );
}
float AudioServerSW::voice_get_filter_resonance(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_filter_resonance( v->channel );
}
float AudioServerSW::voice_get_chorus(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_chorus( v->channel );
}
AS::ReverbRoomType AudioServerSW::voice_get_reverb_type(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, REVERB_SMALL);
return (AS::ReverbRoomType)mixer->channel_get_reverb_type( v->channel );
}
float AudioServerSW::voice_get_reverb(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_reverb( v->channel );
}
int AudioServerSW::voice_get_mix_rate(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_get_mix_rate( v->channel );
}
bool AudioServerSW::voice_is_positional(RID p_voice) const {
AUDIO_LOCK
Voice *v = voice_owner.get( p_voice );
ERR_FAIL_COND_V(!v, 0);
return mixer->channel_is_positional( v->channel );
}
void AudioServerSW::voice_stop(RID p_voice) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_STOP;
cmd.voice=p_voice;
voice_rb.push_command(cmd);
//return mixer->channel_free( v->channel );
}
bool AudioServerSW::voice_is_active(RID p_voice) const {
Voice *v = voice_owner.get(p_voice);
ERR_FAIL_COND_V(!v,false);
return v->active;
}
/* STREAM API */
RID AudioServerSW::audio_stream_create(AudioStream *p_stream) {
AUDIO_LOCK
Stream *s = memnew(Stream);
s->audio_stream=p_stream;
s->event_stream=NULL;
s->active=false;
s->E=NULL;
s->volume_scale=1.0;
p_stream->set_mix_rate(AudioDriverSW::get_singleton()->get_mix_rate());
return stream_owner.make_rid(s);
}
RID AudioServerSW::event_stream_create(EventStream *p_stream) {
AUDIO_LOCK
Stream *s = memnew(Stream);
s->audio_stream=NULL;
s->event_stream=p_stream;
s->active=false;
s->E=NULL;
s->volume_scale=1.0;
//p_stream->set_mix_rate(AudioDriverSW::get_singleton()->get_mix_rate());
return stream_owner.make_rid(s);
}
void AudioServerSW::stream_set_active(RID p_stream, bool p_active) {
Stream *s = stream_owner.get(p_stream);
ERR_FAIL_COND(!s);
_THREAD_SAFE_METHOD_
if (s->active==p_active)
return;
AUDIO_LOCK;
s->active=p_active;
if (p_active)
s->E=active_audio_streams.push_back(s);
else {
active_audio_streams.erase(s->E);
s->E=NULL;
}
}
bool AudioServerSW::stream_is_active(RID p_stream) const {
Stream *s = stream_owner.get(p_stream);
ERR_FAIL_COND_V(!s,false);
return s->active;
}
void AudioServerSW::stream_set_volume_scale(RID p_stream, float p_scale) {
Stream *s = stream_owner.get(p_stream);
ERR_FAIL_COND(!s);
s->volume_scale=p_scale;
}
float AudioServerSW::stream_set_volume_scale(RID p_stream) const {
Stream *s = stream_owner.get(p_stream);
ERR_FAIL_COND_V(!s,0);
return s->volume_scale;
}
void AudioServerSW::free(RID p_id) {
if(voice_owner.owns(p_id)) {
Voice *v = voice_owner.get(p_id);
AUDIO_LOCK
mixer->channel_free( v->channel );
voice_owner.free(p_id);
memdelete(v);
} else if (stream_owner.owns(p_id)) {
Stream *s=stream_owner.get(p_id);
if (s->active) {
stream_set_active(p_id,false);
}
memdelete(s);
stream_owner.free(p_id);
} else if (sample_manager->is_sample(p_id)) {
AUDIO_LOCK
sample_manager->free(p_id);
}
}
void AudioServerSW::_thread_func(void *self) {
Thread::set_name("AudioServerSW");
AudioServerSW *as=(AudioServerSW *)self;
while (!as->exit_update_thread) {
as->_update_streams(true);
OS::get_singleton()->delay_usec(5000);
}
}
void AudioServerSW::init() {
int latency = GLOBAL_DEF("audio/mixer_latency",10);
internal_buffer_channels=2; // read from driver
internal_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*internal_buffer_channels);
stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels
AudioMixerSW::MixChannels mix_chans = AudioMixerSW::MIX_STEREO;
switch(AudioDriverSW::get_singleton()->get_output_format()) {
case AudioDriverSW::OUTPUT_MONO:
case AudioDriverSW::OUTPUT_STEREO:
mix_chans=AudioMixerSW::MIX_STEREO;
break;
case AudioDriverSW::OUTPUT_QUAD:
case AudioDriverSW::OUTPUT_5_1:
mix_chans=AudioMixerSW::MIX_QUAD;
break;
}
mixer = memnew( AudioMixerSW( sample_manager, latency, AudioDriverSW::get_singleton()->get_mix_rate(),mix_chans,mixer_use_fx,mixer_interp,_mixer_callback,this ) );
mixer_step_usecs=mixer->get_step_usecs();
_output_delay=0;
stream_volume=0.3;
// start the audio driver
if (AudioDriverSW::get_singleton())
AudioDriverSW::get_singleton()->start();
#ifndef NO_THREADS
exit_update_thread=false;
thread = Thread::create(_thread_func,this);
#endif
}
void AudioServerSW::finish() {
#ifndef NO_THREADS
exit_update_thread=true;
Thread::wait_to_finish(thread);
memdelete(thread);
#endif
if (AudioDriverSW::get_singleton())
AudioDriverSW::get_singleton()->finish();
memdelete_arr(internal_buffer);
memdelete_arr(stream_buffer);
memdelete(mixer);
}
void AudioServerSW::_update_streams(bool p_thread) {
_THREAD_SAFE_METHOD_
for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
List<Stream*>::Element *N=E->next();
if (E->get()->audio_stream && p_thread == E->get()->audio_stream->can_update_mt())
E->get()->audio_stream->update();
E=N;
}
}
void AudioServerSW::update() {
_update_streams(false);
#ifdef NO_THREADS
_update_streams(true);
#endif
}
void AudioServerSW::lock() {
AudioDriverSW::get_singleton()->lock();
}
void AudioServerSW::unlock() {
AudioDriverSW::get_singleton()->unlock();
}
int AudioServerSW::get_default_mix_rate() const {
return AudioDriverSW::get_singleton()->get_mix_rate();
}
int AudioServerSW::get_default_channel_count() const {
return internal_buffer_channels;
}
void AudioServerSW::set_mixer_params(AudioMixerSW::InterpolationType p_interp, bool p_use_fx) {
mixer_interp=p_interp;
mixer_use_fx=p_use_fx;
}
void AudioServerSW::set_stream_global_volume_scale(float p_volume) {
stream_volume_scale=p_volume;
}
float AudioServerSW::get_stream_global_volume_scale() const {
return stream_volume_scale;
}
void AudioServerSW::set_fx_global_volume_scale(float p_volume) {
fx_volume_scale=p_volume;
//mixer->set_mixer_volume(fx_volume_scale);
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_CHANGE_ALL_FX_VOLUMES;
cmd.voice=RID();
cmd.volume.volume=p_volume;
voice_rb.push_command(cmd);
}
float AudioServerSW::get_fx_global_volume_scale() const {
return fx_volume_scale;
}
void AudioServerSW::set_event_voice_global_volume_scale(float p_volume) {
event_voice_volume_scale=p_volume;
//mixer->set_mixer_volume(event_voice_volume_scale);
}
float AudioServerSW::get_event_voice_global_volume_scale() const {
return event_voice_volume_scale;
}
double AudioServerSW::get_output_delay() const {
return _output_delay+AudioDriverSW::get_singleton()->get_latency();
}
double AudioServerSW::get_mix_time() const {
return AudioDriverSW::get_singleton()->get_mix_time();
}
uint32_t AudioServerSW::read_output_peak() const {
uint32_t val = max_peak;
uint32_t *p = (uint32_t*)&max_peak;
*p=0;
return val;
}
AudioServerSW::AudioServerSW(SampleManagerSW *p_sample_manager) {
sample_manager=p_sample_manager;
String interp = GLOBAL_DEF("audio/mixer_interp","linear");
Globals::get_singleton()->set_custom_property_info("audio/mixer_interp",PropertyInfo(Variant::STRING,"audio/mixer_interp",PROPERTY_HINT_ENUM,"raw,linear,cubic"));
if (interp=="raw")
mixer_interp=AudioMixerSW::INTERPOLATION_RAW;
else if (interp=="cubic")
mixer_interp=AudioMixerSW::INTERPOLATION_CUBIC;
else
mixer_interp=AudioMixerSW::INTERPOLATION_LINEAR;
mixer_use_fx = GLOBAL_DEF("audio/use_chorus_reverb",true);
stream_volume_scale=GLOBAL_DEF("audio/stream_volume_scale",1.0);
fx_volume_scale=GLOBAL_DEF("audio/fx_volume_scale",1.0);
event_voice_volume_scale=GLOBAL_DEF("audio/event_voice_volume_scale",0.5);
max_peak=0;
}
AudioServerSW::~AudioServerSW() {
}
AudioDriverSW *AudioDriverSW::singleton=NULL;
AudioDriverSW *AudioDriverSW::get_singleton() {
return singleton;
}
void AudioDriverSW::set_singleton() {
singleton=this;
}
void AudioDriverSW::audio_server_process(int p_frames,int32_t *p_buffer,bool p_update_mix_time) {
AudioServerSW * audio_server = static_cast<AudioServerSW*>(AudioServer::get_singleton());
if (p_update_mix_time)
update_mix_time(p_frames);
audio_server->driver_process(p_frames,p_buffer);
}
void AudioDriverSW::update_mix_time(int p_frames) {
_mix_amount+=p_frames;
_last_mix_time=OS::get_singleton()->get_ticks_usec();
}
double AudioDriverSW::get_mix_time() const {
double total = (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0;
total+=_mix_amount/(double)get_mix_rate();
return total;
}
AudioDriverSW::AudioDriverSW() {
_last_mix_time=0;
_mix_amount=0;
}
AudioDriverSW *AudioDriverManagerSW::drivers[MAX_DRIVERS];
int AudioDriverManagerSW::driver_count=0;
void AudioDriverManagerSW::add_driver(AudioDriverSW *p_driver) {
ERR_FAIL_COND(driver_count>=MAX_DRIVERS);
drivers[driver_count++]=p_driver;
}
int AudioDriverManagerSW::get_driver_count() {
return driver_count;
}
AudioDriverSW *AudioDriverManagerSW::get_driver(int p_driver) {
ERR_FAIL_INDEX_V(p_driver,driver_count,NULL);
return drivers[p_driver];
}