#include #include #include #include #include "channel.h" #include "sound.h" void channel_init(struct channel_t *chan) { chan->active = false; chan->paused = false; chan->volume = 255; chan->pan_left = -128; chan->pan_right = 128; chan->sound_mutex = p_mutex_new(); chan->sound.left = NULL; chan->sound.right = NULL; chan->pos = 0; } void channel_reset(struct channel_t *chan) { p_atomic_int_set(&(chan->paused), false); chan->pos = 0; p_atomic_int_set(&(chan->active), false); } void channel_pause(struct channel_t *chan) { p_atomic_int_set(&(chan->paused), true); } void channel_resume(struct channel_t *chan) { p_atomic_int_set(&(chan->paused), false); } void channel_set_volume(struct channel_t *chan, float volume) { if (volume > 1.0f) volume = 1.0f; if (volume < 0.0f) volume = 0.0f; p_atomic_int_set(&(chan->volume), 255*volume); } void channel_set_pan(struct channel_t *chan, float pan_left, float pan_right) { if (pan_left > 1.0f) pan_left = 1.0f; if (pan_left < -1.0f) pan_left = -1.0f; if (pan_right > 1.0f) pan_right = 1.0f; if (pan_right < -1.0f) pan_right = -1.0f; p_atomic_int_set(&(chan->pan_left), 128*pan_left); p_atomic_int_set(&(chan->pan_right), 128*pan_right); } int channel_sound_load(struct channel_t *chan, struct mossrose_sound_t *sound, bool force) { if (!force && p_atomic_int_get(&(chan->active))) /* active, fail! */ return 1; p_mutex_lock(chan->sound_mutex); sound_copy(&(chan->sound), sound); chan->pos = 0; p_atomic_int_set(&(chan->paused), false); if (!force) { /* overwrite channel settings */ p_atomic_int_set(&(chan->volume), 255); if (sound->mono) { p_atomic_int_set(&(chan->pan_left), 0); p_atomic_int_set(&(chan->pan_right), 0); } else { /* stereo */ p_atomic_int_set(&(chan->pan_left), -128); p_atomic_int_set(&(chan->pan_right), 128); } } p_mutex_unlock(chan->sound_mutex); p_atomic_int_set(&(chan->active), true); return 0; } #define QUARTER_PI 0.785397 static void pan_gain(float *gain_l, float *gain_r, float pan) { float theta = (QUARTER_PI * pan) + QUARTER_PI; /* 0-PI/2 */ *gain_l = cos(theta); *gain_r = sin(theta); } void channel_get_next_sample(float *left, float *right, struct channel_t *chan) { bool active = p_atomic_int_get(&(chan->active)); bool paused = p_atomic_int_get(&(chan->paused)); if (!active || paused) { /* skip this channel */ *left = 0; *right = 0; return; } if (!p_mutex_trylock(chan->sound_mutex)) { /* can't lock mutex, skip */ *left = 0; *right = 0; return; } float volume = ((float)p_atomic_int_get(&(chan->volume)))/255; if (chan->sound.mono) { float x = chan->sound.left[chan->pos]; float pan = ((float)p_atomic_int_get(&(chan->pan_left)))/128; float gain_l, gain_r; pan_gain(&gain_l, &gain_r, pan); *left = volume * gain_l * x; *right = volume * gain_r * x; } else { float l, r; l = chan->sound.left[chan->pos]; r = chan->sound.right[chan->pos]; float pan_l = ((float)p_atomic_int_get(&(chan->pan_left)))/128; float pan_r = ((float)p_atomic_int_get(&(chan->pan_right)))/128; float gain_ll, gain_lr, gain_rl, gain_rr; pan_gain(&gain_ll, &gain_lr, pan_l); pan_gain(&gain_rl, &gain_rr, pan_r); *left = volume * ((gain_ll * l) + (gain_rl * r)); *right = volume * ((gain_lr * l) + (gain_rr * r)); } chan->pos += 1; if (chan->pos >= chan->sound.len) { channel_reset(chan); } p_mutex_unlock(chan->sound_mutex); }