#define AUDIO_EDIT_OWNERSHIP 0x40
#define AUDIO_EDIT_SAMPLING_RATE 0x80
-void audio_channel_init( audio_channel *ch, audio_clip *clip, u32 flags )
-{
- audio_require_lock();
- ch->group = 0;
- ch->clip = clip;
- ch->flags = flags;
- ch->colour = 0x00333333;
-
- if( (ch->clip->flags & AUDIO_FLAG_FORMAT) == k_audio_format_bird )
- strcpy( ch->name, "[array]" );
- else if( (ch->clip->flags & AUDIO_FLAG_FORMAT) == k_audio_format_gen )
- strcpy( ch->name, "[program]" );
- else
- vg_strncpy( clip->path, ch->name, 32, k_strncpy_always_add_null );
-
- ch->allocated = 1;
-
- ch->editable_state.relinquished = 0;
- ch->editable_state.volume = 1.0f;
- ch->editable_state.volume_target = 1.0f;
- ch->editable_state.pan = 0.0f;
- ch->editable_state.pan_target = 0.0f;
- ch->editable_state.volume_rate = 0;
- ch->editable_state.pan_rate = 0;
- v4_copy((v4f){0.0f,0.0f,0.0f,1.0f},ch->editable_state.spacial_falloff);
- ch->editable_state.lfo = NULL;
- ch->editable_state.lfo_amount = 0.0f;
- ch->editable_state.sampling_rate = 1.0f;
- ch->editble_state_write_mask = 0x00;
-}
-
-void audio_channel_group( audio_channel *ch, u16 group )
-{
- audio_require_lock();
- ch->group = group;
- ch->colour = (((u32)group * 29986577) & 0x00ffffff) | 0xff000000;
-}
-
-audio_channel *audio_get_first_idle_channel(void)
-{
- audio_require_lock();
- for( int i=0; i<AUDIO_CHANNELS; i++ ){
- audio_channel *ch = &vg_audio.channels[i];
-
- if( !ch->allocated ){
- return ch;
- }
- }
-
- return NULL;
-}
-
-audio_channel *audio_get_group_idle_channel( u16 group, u32 max_count )
-{
- audio_require_lock();
- u32 count = 0;
- audio_channel *dest = NULL;
-
- for( int i=0; i<AUDIO_CHANNELS; i++ ){
- audio_channel *ch = &vg_audio.channels[i];
-
- if( ch->allocated ){
- if( ch->group == group ){
- count ++;
- }
- }
- else{
- if( !dest )
- dest = ch;
- }
- }
-
- if( dest && (count < max_count) ){
- return dest;
- }
-
- return NULL;
-}
-
-audio_channel *audio_get_group_first_active_channel( u16 group )
-{
- audio_require_lock();
- for( int i=0; i<AUDIO_CHANNELS; i++ ){
- audio_channel *ch = &vg_audio.channels[i];
- if( ch->allocated && (ch->group == group) )
- return ch;
- }
- return NULL;
-}
-
int audio_channel_finished( audio_channel *ch )
{
audio_require_lock();
return 0;
}
-audio_channel *audio_relinquish_channel( audio_channel *ch )
-{
- audio_require_lock();
- ch->editable_state.relinquished = 1;
- ch->editble_state_write_mask |= AUDIO_EDIT_OWNERSHIP;
- return NULL;
-}
-
-void audio_channel_slope_volume( audio_channel *ch, f32 length, f32 new_vol )
-{
- audio_require_lock();
- ch->editable_state.volume_target = new_vol;
- ch->editable_state.volume_rate = length * 44100.0f;
- ch->editble_state_write_mask |= AUDIO_EDIT_VOLUME_SLOPE;
-}
-
-void audio_channel_set_sampling_rate( audio_channel *ch, float rate )
-{
- audio_require_lock();
- ch->editable_state.sampling_rate = rate;
- ch->editble_state_write_mask |= AUDIO_EDIT_SAMPLING_RATE;
-}
-
-/* Review: this is never called with instant set to 1 */
-void audio_channel_edit_volume( audio_channel *ch, f32 new_vol, int instant )
-{
- audio_require_lock();
- if( instant )
- {
- ch->editable_state.volume = new_vol;
- ch->editble_state_write_mask |= AUDIO_EDIT_VOLUME;
- }
- else
- {
- audio_channel_slope_volume( ch, 0.05f, new_vol );
- }
-}
-
-audio_channel *audio_channel_fadeout( audio_channel *ch, float length )
-{
- audio_require_lock();
- audio_channel_slope_volume( ch, length, 0.0f );
- return audio_relinquish_channel( ch );
-}
-
-void audio_channel_fadein( audio_channel *ch, float length )
-{
- audio_require_lock();
- audio_channel_edit_volume( ch, 0.0f, 1 );
- audio_channel_slope_volume( ch, length, 1.0f );
-}
-
-audio_channel *audio_channel_crossfade( audio_channel *ch,
- audio_clip *new_clip,
- float length, u32 flags )
-{
- audio_require_lock();
- u32 cursor = 0;
-
- if( ch )
- ch = audio_channel_fadeout( ch, length );
-
- audio_channel *replacement = audio_get_first_idle_channel();
-
- if( replacement ){
- audio_channel_init( replacement, new_clip, flags );
- audio_channel_fadein( replacement, length );
- }
-
- return replacement;
-}
-
-void audio_channel_sidechain_lfo( audio_channel *ch, int lfo_id, f32 amount )
-{
- audio_require_lock();
- ch->editable_state.lfo = &vg_audio.oscillators[ lfo_id ];
- ch->editable_state.lfo_amount = amount;
- ch->editble_state_write_mask |= AUDIO_EDIT_LFO_ATTACHMENT;
-}
-
-void audio_channel_set_spacial( audio_channel *ch, v3f co, float range )
-{
- audio_require_lock();
- if( ch->flags & AUDIO_FLAG_SPACIAL_3D ){
- v3_copy( co, ch->editable_state.spacial_falloff );
-
- if( range == 0.0f )
- ch->editable_state.spacial_falloff[3] = 1.0f;
- else
- ch->editable_state.spacial_falloff[3] = 1.0f/range;
-
- ch->editble_state_write_mask |= AUDIO_EDIT_SPACIAL;
- }
- else{
- vg_warn( "Tried to set spacialization paramaters for 2D channel (%s)\n",
- ch->name );
- }
-}
-
-audio_channel *audio_oneshot_3d( audio_clip *clip, v3f position,
- f32 range, f32 volume )
-{
- audio_require_lock();
- audio_channel *ch = audio_get_first_idle_channel();
-
- if( ch )
- {
- audio_channel_init( ch, clip, AUDIO_FLAG_SPACIAL_3D );
- audio_channel_set_spacial( ch, position, range );
- audio_channel_edit_volume( ch, volume, 1 );
- audio_relinquish_channel( ch );
-
- return ch;
- }
- else
- return NULL;
-}
-
-audio_channel *audio_oneshot( audio_clip *clip, f32 volume, f32 pan )
-{
- audio_require_lock();
- audio_channel *ch = audio_get_first_idle_channel();
-
- if( ch )
- {
- audio_channel_init( ch, clip, AUDIO_FLAG_NO_DSP );
- audio_channel_edit_volume( ch, volume, 1 );
- audio_relinquish_channel( ch );
-
- return ch;
- }
- else
- return NULL;
-}
-
-void audio_set_lfo_wave( int id, enum lfo_wave_type type, f32 coefficient )
-{
- audio_require_lock();
- audio_lfo *lfo = &vg_audio.oscillators[ id ];
- lfo->editable_state.polynomial_coefficient = coefficient;
- lfo->editable_state.wave_type = type;
-
- lfo->editble_state_write_mask |= AUDIO_EDIT_LFO_WAVE;
-}
-
-void audio_set_lfo_frequency( int id, float freq )
-{
- audio_require_lock();
- audio_lfo *lfo = &vg_audio.oscillators[ id ];
- lfo->editable_state.period = 44100.0f / freq;
- lfo->editble_state_write_mask |= AUDIO_EDIT_LFO_PERIOD;
-}
-
-
/*
* Committers
* -----------------------------------------------------------------------------
+_Thread_local static bool _vg_audio_thread_has_lock = 0;
+
+void vg_audio_lock(void)
+{
+ SDL_LockMutex( _vg_audio.mutex );
+ _vg_audio_thread_has_lock = 1;
+}
+
+void vg_audio_unlock(void)
+{
+ _vg_audio_thread_has_lock = 0;
+ SDL_UnlockMutex( _vg_audio.mutex );
+}
+
+static void vg_audio_assert_lock(void)
+{
+ if( _vg_audio_thread_has_lock == 0 )
+ {
+ vg_error( "vg_audio function requires locking\n" );
+ abort();
+ }
+}
+/* main channels
+ * ---------------------------------------------------------------------------------------- */
+audio_channel *audio_get_first_idle_channel(void)
+{
+ vg_audio_assert_lock();
+ for( int i=0; i<AUDIO_CHANNELS; i++ )
+ {
+ audio_channel *channel = &_vg_audio.channels[i];
+ if( channel->activity == k_channel_activity_none )
+ {
+ channel->activity = k_channel_activity_allocating;
+ channel->ui_name[0] = 0;
+ channel->ui_colour[0] = 0x00333333;
+ channel->flags = 0x00;
+ channel->group = 0;
+ channel->clip = NULL;
+ channel->clip_length = 0;
+ channel->decoder_handle.bird = NULL;
+ channel->cursor = 0;
+ channel->volume = AUDIO_VOLUME_100;
+ channel->volume_target = AUDIO_VOLUME_100;
+ channel->volume_slew_rate_per_sample = AUDIO_VOLUME_100 / (44100*10); /* 1/10th second */
+ channel->pan = 0;
+ channel->pan_target = 0;
+ channel->pan_slew_rate_per_sample = AUDIO_PAN_RIGHT_100 / (44100*10);
+ channel->sampling_rate_multiplier = 1.0f;
+ v4_copy( (v4f){0,0,0,1}, channel->spacial_falloff );
+ channel->lfo = NULL;
+ channel->lfo_attenuation_amount = 0.0f;
+ return channel;
+ }
+ }
+ return NULL;
+}
+void vg_audio_set_channel_clip( audio_channel *channel, audio_clip *clip )
+{
+ vg_audio_assert_lock();
+ VG_ASSERT( channel->activity == k_channel_activity_allocating );
+ VG_ASSERT( channel->clip == NULL );
+ channel->clip = clip;
+
+ u32 audio_format = channel->clip->flags & AUDIO_FLAG_FORMAT;
+ if( audio_format == k_audio_format_bird )
+ strcpy( channel->name, "[array]" );
+ else if( audio_format == k_audio_format_gen )
+ strcpy( channel->name, "[program]" );
+ else
+ vg_strncpy( clip->path, channel->name, 32, k_strncpy_always_add_null );
+}
+
+void vg_audio_set_channel_group( audio_channel *channel, u16 group )
+{
+ vg_audio_assert_lock();
+ VG_ASSERT( channel->activity == k_channel_activity_allocating );
+ VG_ASSERT( channel->group = NULL );
+ channel->group = group;
+ if( group )
+ channel->ui_colour = (((u32)group * 29986577) & 0x00ffffff) | 0xff000000;
+}
+
+u32 vg_audio_count_channels_in_group( u16 group )
+{
+ vg_audio_assert_lock();
+
+ u32 count = 0;
+ for( int i=0; i<AUDIO_CHANNELS; i++ )
+ {
+ audio_channel *channel = &_vg_audio.channels[i];
+
+ if( channel->activity != k_channel_activity_none )
+ count ++;
+ }
+
+ return count;
+}
+
+audio_channel *vg_audio_get_first_active_channel_in_group( u16 group )
+{
+ vg_audio_assert_lock();
+ for( int i=0; i<AUDIO_CHANNELS; i++ )
+ {
+ audio_channel *channel = &_vg_audio.channels[i];
+ if( (channel->activity != k_channel_activity_none) && (channel->group == group) )
+ return channel;
+ }
+ return NULL;
+}
+
+void vg_audio_sidechain_lfo_to_channel( audio_channel *channel, audio_lfo *lfo, f32 amount )
+{
+ vg_audio_assert_lock();
+ channel->lfo = lfo;
+ channel->lfo_attenuation_amount = ammount;
+}
+
+void vg_audio_set_channel_spacial_falloff( audio_channel *channel, v3f co, f32 range )
+{
+ vg_audio_assert_lock();
+ channel->flags |= AUDIO_FLAG_SPACIAL_3D;
+ v3_copy( co, channel->spacial_falloff );
+ channel->spacial_falloff[3] = range == 0.0f? 1.0f: 1.0f/range;
+}
+
+void vg_audio_set_channel_volume( audio_channel *channel, f64 volume, bool instant )
+{
+ vg_audio_assert_lock();
+ channel->volume_target = ((f64)AUDIO_VOLUME_100) * volume;
+
+ if( instant )
+ channel->volume = channel->volume_target;
+}
+
+void vg_audio_set_channel_volume_slew_duration( audio_channel *channel, f64 length_seconds )
+{
+ vg_audio_assert_lock();
+ channel->volume_slew_rate_per_sample = (f64)AUDIO_VOLUME_100 / (length_seconds * 44100.0);
+}
+
+void vg_audio_set_channel_pan_slew_duration( audio_channel *channel, f64 length_seconds )
+{
+ vg_audio_assert_lock();
+ channel->pan_slew_rate_per_sample = (f64)AUDIO_PAN_RIGHT_100 / (length_seconds * 44100.0);
+}
+
+void vg_audio_relinquish_channel( audio_channel *channel )
+{
+ vg_audio_assert_lock();
+ channel->flags |= AUDIO_FLAG_RELINQUISHED;
+}
+
+void vg_audio_channel_start( audio_channel *channel )
+{
+ vg_audio_assert_lock();
+ VG_ASSERT( channel->activity == k_channel_activity_allocation );
+ VG_ASSERT( channel->clip );
+ channel->activity = k_channel_activity_wake;
+}
+
+audio_channel *vg_audio_crossfade( audio_channel *channel, audio_clip *new_clip, f32 transition_seconds )
+{
+ vg_audio_assert_lock();
+ VG_ASSERT( channel );
+
+ vg_audio_set_channel_volume_slew_duration( channel, transition_seconds );
+ vg_audio_set_channel_volume( channel, 0.0 );
+ vg_audio_relinquish_channel( channel );
+
+ audio_channel *replacement = vg_audio_get_first_idle_channel();
+
+ if( replacement )
+ {
+ vg_audio_set_channel_clip( replacement, new_clip );
+ vg_audio_set_channel_volume_slew_duration( replacement, transition_seconds );
+ vg_audio_set_channel_volume( replacement, 1.0 );
+ vg_audio_set_channel_group( replacement, channel->group );
+ replacement->flags = channel->flags;
+ replacement->lfo = channel->lfo;
+ replacement->lfo_attenuation_amount = channel->attenuation_amount;
+ v4_copy( channel->spacial_falloff, replacement->spacial_falloff );
+ vg_audio_channel_start( replacement );
+ }
+
+ return replacement;
+}
+
+void vg_audio_oneshot_3d( audio_clip *clip, v3f co, f32 range, f32 volume, u16 group )
+{
+ vg_audio_assert_lock();
+ audio_channel *channel = vg_audio_get_first_idle_channel();
+
+ if( channel )
+ {
+ vg_audio_set_channel_clip( channel, clip );
+ vg_audio_set_channel_spacial_falloff( channel, co, range );
+ vg_audio_set_channel_group( channel, group );
+ vg_audio_set_
+ vg_audio_start_channel( channel );
+
+ audio_channel_edit_volume( ch, volume, 1 );
+ audio_relinquish_channel( ch );
+ }
+}
+
+audio_channel *audio_oneshot( audio_clip *clip, f32 volume, f32 pan )
+{
+ audio_require_lock();
+ audio_channel *ch = audio_get_first_idle_channel();
+
+ if( ch )
+ {
+ audio_channel_init( ch, clip, AUDIO_FLAG_NO_DSP );
+ audio_channel_edit_volume( ch, volume, 1 );
+ audio_relinquish_channel( ch );
+
+ return ch;
+ }
+ else
+ return NULL;
+}
+
+
+
+/* lfos
+ * ---------------------------------------------------------------------------------------- */
+
+audio_lfo *vg_audio_get_first_idle_lfo(void)
+{
+ vg_audio_assert_lock();
+
+ for( int i=0; i<AUDIO_LFOS; i++ )
+ {
+ audio_lfo *lfo = &_vg_audio.lfos[i];
+
+ if( lfo->activity == k_channel_activity_none )
+ {
+ lfo->activity = k_channel_activity_allocation;
+ lfo->time = 0;
+ lfo->period_in_samples = 44100;
+ lfo->last_period_in_samples = 4410;
+ lfo->wave_type = k_lfo_triangle;
+ lfo->polynomial_coefficient = 0.0f;
+ lfo->flags = 0x00;
+ return lfo;
+ }
+ }
+
+ return NULL;
+}
+
+void vg_audio_set_lfo_polynomial_bipolar( audio_lfo *lfo, f32 coefficient )
+{
+ vg_audio_assert_lock();
+
+ lfo->polynomial_coefficient = coefficient;
+ lfo->wave_type = k_lfo_polynomial_bipolar;
+}
+
+void vg_audio_set_lfo_frequency( audio_lfo *lfo, f32 freq )
+{
+ vg_audio_assert_lock();
+
+ u32 length = 44100.0f / freq;
+ lfo->period_in_samples = length;
+
+ if( lfo->activity == k_channel_activity_allocation )
+ lfo->last_period_in_samples = length;
+}
+
+void vg_audio_start_lfo( audio_lfo *lfo )
+{
+ vg_audio_assert_lock();
+ lfo->activity = k_achannel_activity_alive;
+}
vg_console_reg_var( "vg_dsp", &_vg_audio.dsp_enabled, k_var_dtype_i32, VG_VAR_PERSISTENT );
}
-void audio_lock(void)
-{
- SDL_LockMutex( _vg_audio.mutex );
-}
-
-void audio_unlock(void)
-{
- SDL_UnlockMutex( _vg_audio.mutex );
-}
-
void vg_audio_device_init(void)
{
SDL_AudioSpec spec_desired, spec_got;
#define AUDIO_DECODE_SIZE (1024*256) /* 256 kb decoding buffers */
-#define AUDIO_VOLUME_100 500000000
+#define AUDIO_VOLUME_100 500000000
+#define AUDIO_PAN_RIGHT_100 500000000
+#define AUDIO_PAN_LEFT_100 -500000000
typedef struct audio_clip audio_clip;
typedef struct audio_channel audio_channel;
typedef struct audio_lfo audio_lfo;
+enum channel_activity
+{
+ k_channel_activity_none,
+ k_channel_activity_allocation,
+ k_channel_activity_wake,
+ k_channel_activity_alive,
+ k_channel_activity_pause,
+ k_channel_activity_end,
+ k_channel_activity_error
+};
+
struct audio_clip
{
union
struct audio_lfo
{
- u32 time, period_in_samples;
+ enum channel_activity activity;
+ u32 time, period_in_samples, last_period_in_samples;
enum lfo_wave_type
{
struct audio_channel
{
+ enum channel_activity activity;
+
/* properties */
char ui_name[32];
u32 ui_colour;
u32 flags;
u16 group;
- enum channel_activity
- {
- k_channel_activity_none,
- k_channel_activity_allocation,
- k_channel_activity_alive,
- k_channel_activity_pause,
- k_channel_activity_end,
- k_channel_activity_error
- }
- activity;
-
audio_clip *clip;
u32 clip_length;
void audio_clip_load( audio_clip *clip, void *lin_alloc );
void audio_clip_loadn( audio_clip *arr, int count, void *lin_alloc );
-void audio_lock(void);
-void audio_unlock(void);
+void vg_audio_lock(void);
+void vg_audio_unlock(void);
-void audio_channel_init( audio_channel *ch, audio_clip *clip, u32 flags );
-void audio_channel_group( audio_channel *ch, u16 group );
-audio_channel *audio_get_first_idle_channel(void);
-audio_channel *audio_get_group_idle_channel( u16 group, u32 max_count );
-audio_channel *audio_get_group_first_active_channel( u16 group );
+void vg_audio_channel_init( audio_channel *ch, audio_clip *clip, u32 flags );
+void vg_audio_channel_group( audio_channel *ch, u16 group );
+audio_channel *vg_audio_get_first_idle_channel(void);
+audio_channel *vg_audio_get_group_idle_channel( u16 group, u32 max_count );
+audio_channel *vg_audio_get_group_first_active_channel( u16 group );
+
+audio_lfo *vg_audio_get_first_idle_lfo(void);
#if 0
void vg_audio_init(void);
void vg_audio_free(void);
-void audio_lock(void);
-void audio_unlock(void);
+void vg_audio_lock(void);
+void vg_audio_unlock(void);
void audio_channel_init( audio_channel *ch, audio_clip *clip, u32 flags );
void audio_channel_group( audio_channel *ch, u16 group );