1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
9 #include "vg/vg_stdint.h"
10 #include "vg/vg_platform.h"
14 #include "vg/vg_console.h"
15 #include "vg/vg_store.h"
16 #include "vg/vg_profiler.h"
23 #pragma GCC push_options
24 #pragma GCC optimize ("O3")
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
30 #define STB_VORBIS_MAX_CHANNELS 2
31 #include "submodules/stb/stb_vorbis.c"
38 #pragma GCC pop_options
39 #pragma GCC diagnostic pop
43 #define AUDIO_CHANNELS 32
45 #define AUDIO_FLAG_LOOP 0x1
46 #define AUDIO_FLAG_SPACIAL_3D 0x2
48 /* Vorbis will ALWAYS use the maximum amount of channels it can */
49 //#define AUDIO_FLAG_MONO 0x100 NOTE: This is the default, so its not used
50 #define AUDIO_FLAG_STEREO 0x200
51 #define AUDIO_FLAG_VORBIS 0x400
53 #define AUDIO_DECODE_SIZE (1024*256) /* 256 kb decoding buffers */
54 #define AUDIO_MUTE_VOLUME 0.0f
55 #define AUDIO_BASE_VOLUME 1.0f
57 typedef struct audio_clip audio_clip
;
58 typedef struct audio_channel audio_channel
;
59 typedef struct audio_lfo audio_lfo
;
70 static struct vg_audio_system
72 SDL_AudioDeviceID sdl_output_device
;
81 SDL_mutex
*mux_checker
,
86 u32 time
, time_startframe
;
87 float sqrt_polynomial_coefficient
;
96 k_lfo_polynomial_bipolar
101 float polynomial_coefficient
;
104 u32 editble_state_write_mask
;
106 oscillators
[ AUDIO_LFOS
];
111 char name
[32]; /* only editable while allocated == 0 */
112 audio_clip
*source
; /* ... */
115 /* internal non-readable state
116 * -----------------------------*/
117 u32 cursor
, source_length
;
119 float volume_movement_start
,
125 stb_vorbis
*vorbis_handle
;
126 stb_vorbis_alloc vorbis_alloc
;
128 enum channel_activity
130 k_channel_activity_reset
, /* will advance if allocated==1, to wake */
131 k_channel_activity_wake
, /* will advance to either of next two */
132 k_channel_activity_alive
,
133 k_channel_activity_error
138 * editable structure, can be modified inside _lock and _unlock
139 * the edit mask tells which to copy into internal _, or to discard
140 * ----------------------------------------------------------------------
146 float volume
, /* current volume */
147 volume_target
, /* target volume */
155 v4f spacial_falloff
; /* xyz, range */
161 u32 editble_state_write_mask
;
163 channels
[ AUDIO_CHANNELS
];
165 /* System queue, and access from thread 0 */
166 int debug_ui
, debug_ui_3d
;
173 volume_target_internal
,
176 vg_audio
= { .volume_console
= 1.0f
};
179 static struct vg_profile
180 _vg_prof_audio_decode
= {.mode
= k_profile_mode_accum
,
181 .name
= "[T2] audio_decode()"},
182 _vg_prof_audio_mix
= {.mode
= k_profile_mode_accum
,
183 .name
= "[T2] audio_mix()"},
184 vg_prof_audio_decode
,
188 * These functions are called from the main thread and used to prevent bad
189 * access. TODO: They should be no-ops in release builds.
191 VG_STATIC
int audio_lock_checker_load(void)
194 SDL_LockMutex( vg_audio
.mux_checker
);
195 value
= vg_audio
.sync_locked
;
196 SDL_UnlockMutex( vg_audio
.mux_checker
);
200 VG_STATIC
void audio_lock_checker_store( int value
)
202 SDL_LockMutex( vg_audio
.mux_checker
);
203 vg_audio
.sync_locked
= value
;
204 SDL_UnlockMutex( vg_audio
.mux_checker
);
207 VG_STATIC
void audio_require_lock(void)
209 if( audio_lock_checker_load() )
212 vg_error( "Modifying sound effects systems requires locking\n" );
216 VG_STATIC
void audio_lock(void)
218 SDL_LockMutex( vg_audio
.mux_sync
);
219 audio_lock_checker_store(1);
222 VG_STATIC
void audio_unlock(void)
224 audio_lock_checker_store(0);
225 SDL_UnlockMutex( vg_audio
.mux_sync
);
228 VG_STATIC
void audio_mixer_callback( void *user
, u8
*stream
, int frame_count
);
229 VG_STATIC
void vg_audio_init(void)
231 vg_audio
.mux_checker
= SDL_CreateMutex();
232 vg_audio
.mux_sync
= SDL_CreateMutex();
234 /* TODO: Move here? */
235 vg_var_push( (struct vg_var
){
236 .name
= "debug_audio",
237 .data
= &vg_audio
.debug_ui
,
238 .data_type
= k_var_dtype_i32
,
239 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
243 vg_var_push( (struct vg_var
){
245 .data
= &vg_audio
.volume_console
,
246 .data_type
= k_var_dtype_f32
,
247 .opt_f32
= { .min
=0.0f
, .max
=2.0f
, .clamp
=1 },
251 /* allocate memory */
254 vg_audio
.audio_pool
=
255 vg_create_linear_allocator( vg_mem
.rtmemory
, 1024*1024*32,
259 u32 decode_size
= AUDIO_DECODE_SIZE
* AUDIO_CHANNELS
;
260 vg_audio
.decode_buffer
= vg_linear_alloc( vg_mem
.rtmemory
, decode_size
);
262 SDL_AudioSpec spec_desired
, spec_got
;
263 spec_desired
.callback
= audio_mixer_callback
;
264 spec_desired
.channels
= 2;
265 spec_desired
.format
= AUDIO_F32
;
266 spec_desired
.freq
= 44100;
267 spec_desired
.padding
= 0;
268 spec_desired
.samples
= 512;
269 spec_desired
.silence
= 0;
270 spec_desired
.size
= 0;
271 spec_desired
.userdata
= NULL
;
273 vg_audio
.sdl_output_device
=
274 SDL_OpenAudioDevice( NULL
, 0, &spec_desired
, &spec_got
,
275 SDL_AUDIO_ALLOW_SAMPLES_CHANGE
);
277 if( vg_audio
.sdl_output_device
)
279 SDL_PauseAudioDevice( vg_audio
.sdl_output_device
, 0 );
284 "SDL_OpenAudioDevice failed. Your default audio device must support:\n"
285 " Frequency: 44100 hz\n"
286 " Buffer size: 512\n"
288 " Format: s16 or f32\n" );
291 vg_success( "Ready\n" );
294 VG_STATIC
void vg_audio_free(void)
296 SDL_CloseAudioDevice( vg_audio
.sdl_output_device
);
303 #define AUDIO_EDIT_VOLUME_SLOPE 0x1
304 #define AUDIO_EDIT_VOLUME 0x2
305 #define AUDIO_EDIT_LFO_PERIOD 0x4
306 #define AUDIO_EDIT_LFO_WAVE 0x8
307 #define AUDIO_EDIT_LFO_ATTACHMENT 0x10
308 #define AUDIO_EDIT_SPACIAL 0x20
309 #define AUDIO_EDIT_OWNERSHIP 0x40
310 #define AUDIO_EDIT_SAMPLING_RATE 0x80
312 static audio_channel
*audio_request_channel( audio_clip
*clip
, u32 flags
)
314 for( int i
=0; i
<AUDIO_CHANNELS
; i
++ )
316 audio_channel
*ch
= &vg_audio
.channels
[i
];
322 strcpy( ch
->name
, clip
->path
);
326 ch
->editable_state
.relinquished
= 0;
327 ch
->editable_state
.volume
= 1.0f
;
328 ch
->editable_state
.volume_target
= 1.0f
;
329 ch
->editable_state
.pan
= 0.0f
;
330 ch
->editable_state
.pan_target
= 0.0f
;
331 ch
->editable_state
.volume_rate
= 0;
332 ch
->editable_state
.pan_rate
= 0;
333 v4_copy((v4f
){0.0f
,0.0f
,0.0f
,1.0f
},ch
->editable_state
.spacial_falloff
);
334 ch
->editable_state
.lfo
= NULL
;
335 ch
->editable_state
.lfo_amount
= 0.0f
;
336 ch
->editable_state
.sampling_rate
= 1.0f
;
337 ch
->editble_state_write_mask
= 0x00;
345 static audio_channel
*audio_relinquish_channel( audio_channel
*ch
)
347 ch
->editable_state
.relinquished
= 1;
348 ch
->editble_state_write_mask
|= AUDIO_EDIT_OWNERSHIP
;
352 static void audio_channel_slope_volume( audio_channel
*ch
, float length
,
355 ch
->editable_state
.volume_target
= new_volume
;
356 ch
->editable_state
.volume_rate
= length
* 44100.0f
;
357 ch
->editble_state_write_mask
|= AUDIO_EDIT_VOLUME_SLOPE
;
360 static void audio_channel_set_sampling_rate( audio_channel
*ch
, float rate
)
362 ch
->editable_state
.sampling_rate
= rate
;
363 ch
->editble_state_write_mask
|= AUDIO_EDIT_SAMPLING_RATE
;
366 static void audio_channel_edit_volume( audio_channel
*ch
,
367 float new_volume
, int instant
)
371 ch
->editable_state
.volume
= new_volume
;
372 ch
->editble_state_write_mask
|= AUDIO_EDIT_VOLUME
;
376 audio_channel_slope_volume( ch
, 0.05f
, new_volume
);
380 static audio_channel
*audio_channel_fadeout( audio_channel
*ch
, float length
)
382 audio_channel_slope_volume( ch
, length
, 0.0f
);
383 return audio_relinquish_channel( ch
);
386 static void audio_channel_fadein( audio_channel
*ch
, float length
)
388 audio_channel_edit_volume( ch
, 0.0f
, 1 );
389 audio_channel_slope_volume( ch
, length
, 1.0f
);
392 static audio_channel
*audio_channel_crossfade( audio_channel
*ch
,
393 audio_clip
*new_clip
,
394 float length
, u32 flags
)
399 ch
= audio_channel_fadeout( ch
, length
);
401 audio_channel
*replacement
= audio_request_channel( new_clip
, flags
);
404 audio_channel_fadein( replacement
, length
);
409 static void audio_channel_sidechain_lfo( audio_channel
*ch
, int lfo_id
,
412 ch
->editable_state
.lfo
= &vg_audio
.oscillators
[ lfo_id
];
413 ch
->editable_state
.lfo_amount
= amount
;
414 ch
->editble_state_write_mask
|= AUDIO_EDIT_LFO_ATTACHMENT
;
417 static void audio_channel_set_spacial( audio_channel
*ch
, v3f co
, float range
)
419 if( ch
->flags
& AUDIO_FLAG_SPACIAL_3D
)
421 v3_copy( co
, ch
->editable_state
.spacial_falloff
);
422 ch
->editable_state
.spacial_falloff
[3] = 1.0f
/range
;
423 ch
->editble_state_write_mask
|= AUDIO_EDIT_SPACIAL
;
427 vg_warn( "Tried to set spacialization paramaters for 2D channel (%s)\n",
432 static int audio_oneshot_3d( audio_clip
*clip
, v3f position
,
433 float range
, float volume
)
435 audio_channel
*ch
= audio_request_channel( clip
, AUDIO_FLAG_SPACIAL_3D
);
439 audio_channel_set_spacial( ch
, position
, range
);
440 audio_channel_edit_volume( ch
, volume
, 1 );
441 ch
= audio_relinquish_channel( ch
);
449 static int audio_oneshot( audio_clip
*clip
, float volume
, float pan
)
451 audio_channel
*ch
= audio_request_channel( clip
, 0x00 );
455 audio_channel_edit_volume( ch
, volume
, 1 );
456 ch
= audio_relinquish_channel( ch
);
464 static void audio_set_lfo_wave( int id
, enum lfo_wave_type type
,
467 audio_lfo
*lfo
= &vg_audio
.oscillators
[ id
];
468 lfo
->editable_state
.polynomial_coefficient
= coefficient
;
469 lfo
->editable_state
.wave_type
= type
;
471 lfo
->editble_state_write_mask
|= AUDIO_EDIT_LFO_WAVE
;
474 static void audio_set_lfo_frequency( int id
, float freq
)
476 audio_lfo
*lfo
= &vg_audio
.oscillators
[ id
];
477 lfo
->editable_state
.period
= 44100.0f
/ freq
;
478 lfo
->editble_state_write_mask
|= AUDIO_EDIT_LFO_PERIOD
;
483 * -----------------------------------------------------------------------------
485 static int audio_channel_load_source( audio_channel
*ch
)
487 if( ch
->source
->flags
& AUDIO_FLAG_VORBIS
)
489 /* Setup vorbis decoder */
490 u32 index
= ch
- vg_audio
.channels
;
492 u8
*buf
= (u8
*)vg_audio
.decode_buffer
,
493 *loc
= &buf
[AUDIO_DECODE_SIZE
*index
];
495 stb_vorbis_alloc alloc
= {
496 .alloc_buffer
= (char *)loc
,
497 .alloc_buffer_length_in_bytes
= AUDIO_DECODE_SIZE
501 stb_vorbis
*decoder
= stb_vorbis_open_memory(
503 ch
->source
->size
, &err
, &alloc
);
507 vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n",
508 ch
->source
->path
, err
);
513 ch
->source_length
= stb_vorbis_stream_length_in_samples( decoder
);
514 ch
->vorbis_handle
= decoder
;
517 else if( ch
->source
->flags
& AUDIO_FLAG_STEREO
)
519 ch
->source_length
= ch
->source
->size
/ 2;
523 ch
->source_length
= ch
->source
->size
;
529 VG_STATIC
void audio_decode_uncompressed_mono( i16
*src
, u32 count
, float *dst
)
531 for( u32 i
=0; i
<count
; i
++ )
533 dst
[ i
*2 + 0 ] = ((float)src
[i
]) * (1.0f
/32767.0f
);
534 dst
[ i
*2 + 1 ] = ((float)src
[i
]) * (1.0f
/32767.0f
);
539 * adapted from stb_vorbis.h, since the original does not handle mono->stereo
542 stb_vorbis_get_samples_float_interleaved_stereo( stb_vorbis
*f
, float *buffer
,
546 c
= VG_MIN( 1, f
->channels
- 1 );
550 int k
= f
->channel_buffer_end
- f
->channel_buffer_start
;
555 for( int j
=0; j
< k
; ++j
)
557 *buffer
++ = f
->channel_buffers
[ 0 ][f
->channel_buffer_start
+j
];
558 *buffer
++ = f
->channel_buffers
[ c
][f
->channel_buffer_start
+j
];
562 f
->channel_buffer_start
+= k
;
567 if( !stb_vorbis_get_frame_float( f
, NULL
, NULL
))
575 * ........ more wrecked code sorry!
578 stb_vorbis_get_samples_i16_downmixed( stb_vorbis
*f
, i16
*buffer
, int len
)
581 c
= VG_MIN( 1, f
->channels
- 1 );
585 int k
= f
->channel_buffer_end
- f
->channel_buffer_start
;
590 for( int j
=0; j
< k
; ++j
)
592 float sl
= f
->channel_buffers
[ 0 ][f
->channel_buffer_start
+j
],
593 sr
= f
->channel_buffers
[ c
][f
->channel_buffer_start
+j
];
595 *buffer
++ = vg_clampf( 0.5f
*(sl
+sr
), -1.0f
, 1.0f
) * 32767.0f
;
596 //*buffer++ = vg_clampf( sr, -1.0f, 1.0f ) * 32767.0f;
600 f
->channel_buffer_start
+= k
;
605 if( !stb_vorbis_get_frame_float( f
, NULL
, NULL
))
612 static float audio_lfo_pull_sample( audio_lfo
*lfo
)
616 if( lfo
->time
>= lfo
->_
.period
)
620 t
/= (float)lfo
->_
.period
;
622 if( lfo
->_
.wave_type
== k_lfo_polynomial_bipolar
)
639 return (( 2.0f
* lfo
->sqrt_polynomial_coefficient
* t
) /
640 /* --------------------------------------- */
641 ( 1.0f
+ lfo
->_
.polynomial_coefficient
* t
*t
)
651 static void audio_channel_get_samples( audio_channel
*ch
,
652 u32 count
, float *buf
)
654 vg_profile_begin( &_vg_prof_audio_decode
);
656 u32 remaining
= count
;
661 u32 samples_this_run
= VG_MIN( remaining
, ch
->source_length
-ch
->cursor
);
662 remaining
-= samples_this_run
;
664 float *dst
= &buf
[ buffer_pos
* 2 ];
666 if( ch
->source
->flags
& AUDIO_FLAG_STEREO
)
668 for( int i
=0;i
<samples_this_run
; i
++ )
674 else if( ch
->source
->flags
& AUDIO_FLAG_VORBIS
)
676 int read_samples
= stb_vorbis_get_samples_float_interleaved_stereo(
681 if( read_samples
!= samples_this_run
)
683 vg_warn( "Invalid samples read (%s)\n", ch
->source
->path
);
685 for( int i
=0; i
<samples_this_run
; i
++ )
694 i16
*src_buffer
= ch
->source
->data
,
695 *src
= &src_buffer
[ch
->cursor
];
697 audio_decode_uncompressed_mono( src
, samples_this_run
, dst
);
700 ch
->cursor
+= samples_this_run
;
701 buffer_pos
+= samples_this_run
;
703 if( (ch
->flags
& AUDIO_FLAG_LOOP
) && remaining
)
705 if( ch
->source
->flags
& AUDIO_FLAG_VORBIS
)
706 stb_vorbis_seek_start( ch
->vorbis_handle
);
717 buf
[ buffer_pos
*2 + 0 ] = 0.0f
;
718 buf
[ buffer_pos
*2 + 1 ] = 0.0f
;
724 vg_profile_end( &_vg_prof_audio_decode
);
727 static void audio_channel_mix( audio_channel
*ch
,
728 float *buffer
, u32 frame_count
)
730 u32 frames_write
= frame_count
;
732 u32 buffer_length
= frame_count
;
733 if( ch
->_
.sampling_rate
!= 1.0f
)
735 buffer_length
= ceilf( (float)frame_count
* ch
->_
.sampling_rate
) + 1;
738 float *pcf
= alloca( buffer_length
* 2 * sizeof(float) );
740 audio_channel_get_samples( ch
, buffer_length
, pcf
);
741 vg_profile_begin( &_vg_prof_audio_mix
);
744 ch
->_
.lfo
->time
= ch
->_
.lfo
->time_startframe
;
746 float framevol_l
= 1.0f
,
749 if( ch
->flags
& AUDIO_FLAG_SPACIAL_3D
)
751 if( !vg_validf(vg_audio
.listener_pos
[0]) ||
752 !vg_validf(vg_audio
.listener_pos
[1]) ||
753 !vg_validf(vg_audio
.listener_pos
[2]) ||
754 !vg_validf(ch
->_
.spacial_falloff
[0]) ||
755 !vg_validf(ch
->_
.spacial_falloff
[1]) ||
756 !vg_validf(ch
->_
.spacial_falloff
[2]) )
758 vg_error( "NaN listener/world position (%s)\n", ch
->name
);
765 v3_sub( ch
->_
.spacial_falloff
, vg_audio
.listener_pos
, delta
);
767 float dist
= v3_length( delta
),
768 vol
= vg_maxf( 0.0f
, 1.0f
- ch
->_
.spacial_falloff
[3]*dist
);
770 v3_muls( delta
, 1.0f
/dist
, delta
);
771 float pan
= v3_dot( vg_audio
.listener_ears
, delta
);
772 vol
= powf( vol
, 5.0f
);
774 framevol_l
*= (vol
* 0.5f
) * (1.0f
- pan
);
775 framevol_r
*= (vol
* 0.5f
) * (1.0f
+ pan
);
778 for( u32 j
=0; j
<frame_count
; j
++ )
780 if( ch
->volume_movement
< ch
->_
.volume_rate
)
782 ch
->volume_movement
++;
784 float movement_t
= ch
->volume_movement
;
785 movement_t
/= (float)ch
->_
.volume_rate
;
787 ch
->_
.volume
= vg_lerpf( ch
->volume_movement_start
,
792 float vol_norm
= ch
->_
.volume
* ch
->_
.volume
;
795 vol_norm
*= 1.0f
+ audio_lfo_pull_sample(ch
->_
.lfo
) * ch
->_
.lfo_amount
;
797 float vol_l
= vol_norm
* framevol_l
,
798 vol_r
= vol_norm
* framevol_r
,
802 if( ch
->_
.sampling_rate
!= 1.0f
)
804 /* absolutely garbage resampling, but it will do
807 float sample_index
= ch
->_
.sampling_rate
* (float)j
;
808 float t
= vg_fractf( sample_index
);
810 u32 i0
= floorf( sample_index
),
813 sample_l
= pcf
[ i0
*2+0 ]*(1.0f
-t
) + pcf
[ i1
*2+0 ]*t
;
814 sample_r
= pcf
[ i0
*2+1 ]*(1.0f
-t
) + pcf
[ i1
*2+1 ]*t
;
818 sample_l
= pcf
[ j
*2+0 ];
819 sample_r
= pcf
[ j
*2+1 ];
822 buffer
[ j
*2+0 ] += sample_l
* vol_l
;
823 buffer
[ j
*2+1 ] += sample_r
* vol_r
;
826 vg_profile_end( &_vg_prof_audio_mix
);
829 VG_STATIC
void audio_mixer_callback( void *user
, u8
*stream
, int byte_count
)
832 * Copy data and move edit flags to commit flags
833 * ------------------------------------------------------------- */
835 for( int i
=0; i
<AUDIO_CHANNELS
; i
++ )
837 audio_channel
*ch
= &vg_audio
.channels
[i
];
842 /* process relinquishments */
843 if( (ch
->activity
!= k_channel_activity_reset
) && ch
->_
.relinquished
)
845 if( (ch
->cursor
>= ch
->source_length
&& !(ch
->flags
& AUDIO_FLAG_LOOP
))
846 || (ch
->_
.volume
== 0.0f
)
847 || (ch
->activity
== k_channel_activity_error
) )
849 ch
->_
.relinquished
= 0;
851 ch
->activity
= k_channel_activity_reset
;
856 /* process new channels */
857 if( ch
->activity
== k_channel_activity_reset
)
859 ch
->_
= ch
->editable_state
;
861 ch
->source_length
= 0;
862 ch
->activity
= k_channel_activity_wake
;
865 if( ch
->editble_state_write_mask
& AUDIO_EDIT_OWNERSHIP
)
866 ch
->_
.relinquished
= ch
->editable_state
.relinquished
;
868 ch
->editable_state
.relinquished
= ch
->_
.relinquished
;
871 if( ch
->editble_state_write_mask
& AUDIO_EDIT_VOLUME
)
872 ch
->_
.volume
= ch
->editable_state
.volume
;
874 ch
->editable_state
.volume
= ch
->_
.volume
;
877 if( ch
->editble_state_write_mask
& AUDIO_EDIT_VOLUME_SLOPE
)
879 ch
->volume_movement_start
= ch
->_
.volume
;
880 ch
->volume_movement
= 0;
882 ch
->_
.volume_target
= ch
->editable_state
.volume_target
;
883 ch
->_
.volume_rate
= ch
->editable_state
.volume_rate
;
887 ch
->editable_state
.volume_target
= ch
->_
.volume_target
;
888 ch
->editable_state
.volume_rate
= ch
->_
.volume_rate
;
892 if( ch
->editble_state_write_mask
& AUDIO_EDIT_SAMPLING_RATE
)
893 ch
->_
.sampling_rate
= ch
->editable_state
.sampling_rate
;
895 ch
->editable_state
.sampling_rate
= ch
->_
.sampling_rate
;
898 if( ch
->editble_state_write_mask
& AUDIO_EDIT_LFO_ATTACHMENT
)
900 ch
->_
.lfo
= ch
->editable_state
.lfo
;
901 ch
->_
.lfo_amount
= ch
->editable_state
.lfo_amount
;
905 ch
->editable_state
.lfo
= ch
->_
.lfo
;
906 ch
->editable_state
.lfo_amount
= ch
->_
.lfo_amount
;
910 if( ch
->editble_state_write_mask
& AUDIO_EDIT_SPACIAL
)
911 v4_copy( ch
->editable_state
.spacial_falloff
,ch
->_
.spacial_falloff
);
913 v4_copy( ch
->_
.spacial_falloff
,ch
->editable_state
.spacial_falloff
);
916 /* currently readonly, i guess */
917 ch
->editable_state
.pan_target
= ch
->_
.pan_target
;
918 ch
->editable_state
.pan
= ch
->_
.pan
;
919 ch
->editble_state_write_mask
= 0x00;
922 for( int i
=0; i
<AUDIO_LFOS
; i
++ )
924 audio_lfo
*lfo
= &vg_audio
.oscillators
[ i
];
926 if( lfo
->editble_state_write_mask
& AUDIO_EDIT_LFO_WAVE
)
928 lfo
->_
.wave_type
= lfo
->editable_state
.wave_type
;
930 if( lfo
->_
.wave_type
== k_lfo_polynomial_bipolar
)
932 lfo
->_
.polynomial_coefficient
=
933 lfo
->editable_state
.polynomial_coefficient
;
934 lfo
->sqrt_polynomial_coefficient
=
935 sqrtf(lfo
->_
.polynomial_coefficient
);
939 if( lfo
->editble_state_write_mask
& AUDIO_EDIT_LFO_PERIOD
)
944 t
/= (float)lfo
->_
.period
;
946 lfo
->_
.period
= lfo
->editable_state
.period
;
947 lfo
->time
= lfo
->_
.period
* t
;
952 lfo
->_
.period
= lfo
->editable_state
.period
;
956 lfo
->editble_state_write_mask
= 0x00;
964 * ------------------------------------------------------------- */
965 for( int i
=0; i
<AUDIO_CHANNELS
; i
++ )
967 audio_channel
*ch
= &vg_audio
.channels
[i
];
969 if( ch
->activity
== k_channel_activity_wake
)
971 if( audio_channel_load_source( ch
) )
972 ch
->activity
= k_channel_activity_alive
;
974 ch
->activity
= k_channel_activity_error
;
980 * -------------------------------------------------------- */
981 int frame_count
= byte_count
/(2*sizeof(float));
984 float *pOut32F
= (float *)stream
;
985 for( int i
=0; i
<frame_count
*2; i
++ )
988 for( int i
=0; i
<AUDIO_LFOS
; i
++ )
990 audio_lfo
*lfo
= &vg_audio
.oscillators
[i
];
991 lfo
->time_startframe
= lfo
->time
;
994 for( int i
=0; i
<AUDIO_CHANNELS
; i
++ )
996 audio_channel
*ch
= &vg_audio
.channels
[i
];
998 if( ch
->activity
== k_channel_activity_alive
)
999 audio_channel_mix( ch
, pOut32F
, frame_count
);
1003 * Relinquishing conditions
1004 * ------------------------------------------------------------------
1008 /* Profiling information
1009 * ----------------------------------------------- */
1010 vg_profile_increment( &_vg_prof_audio_decode
);
1011 vg_profile_increment( &_vg_prof_audio_mix
);
1012 vg_prof_audio_mix
= _vg_prof_audio_mix
;
1013 vg_prof_audio_decode
= _vg_prof_audio_decode
;
1014 vg_audio
.samples_last
= frame_count
;
1019 VG_STATIC
void audio_clip_load( audio_clip
*clip
, void *lin_alloc
)
1021 if( lin_alloc
== NULL
)
1022 lin_alloc
= vg_audio
.audio_pool
;
1025 /* load in directly */
1026 if( clip
->flags
& AUDIO_FLAG_VORBIS
)
1029 clip
->data
= vg_file_read( lin_alloc
, clip
->path
, &clip
->size
);
1033 vg_fatal_exit_loop( "Audio failed to load" );
1035 float mb
= (float)(clip
->size
) / (1024.0f
*1024.0f
);
1036 vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip
->path
, mb
);
1038 else if( clip
->flags
& AUDIO_FLAG_STEREO
)
1040 vg_fatal_exit_loop( "Unsupported format (Stereo uncompressed)" );
1044 vg_linear_clear( vg_mem
.scratch
);
1047 stb_vorbis_alloc alloc
= {
1048 .alloc_buffer
= vg_linear_alloc( vg_mem
.scratch
, AUDIO_DECODE_SIZE
),
1049 .alloc_buffer_length_in_bytes
= AUDIO_DECODE_SIZE
1052 void *filedata
= vg_file_read( vg_mem
.scratch
, clip
->path
, &fsize
);
1055 stb_vorbis
*decoder
= stb_vorbis_open_memory(
1056 filedata
, fsize
, &err
, &alloc
);
1060 vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n",
1062 vg_fatal_exit_loop( "Vorbis decode error" );
1065 /* only mono is supported in uncompressed */
1066 u32 length_samples
= stb_vorbis_stream_length_in_samples( decoder
),
1067 data_size
= length_samples
* sizeof(i16
);
1070 clip
->data
= vg_linear_alloc( lin_alloc
, vg_align8(data_size
) );
1071 clip
->size
= length_samples
;
1074 int read_samples
= stb_vorbis_get_samples_i16_downmixed(
1075 decoder
, clip
->data
, length_samples
);
1077 if( read_samples
!= length_samples
)
1078 vg_fatal_exit_loop( "Decode error" );
1080 float mb
= (float)(data_size
) / (1024.0f
*1024.0f
);
1081 vg_info( "Loaded audio clip '%s' (%.1fmb) %u samples\n", clip
->path
, mb
,
1086 VG_STATIC
void audio_clip_loadn( audio_clip
*arr
, int count
, void *lin_alloc
)
1088 for( int i
=0; i
<count
; i
++ )
1089 audio_clip_load( &arr
[i
], lin_alloc
);
1092 VG_STATIC
void audio_require_clip_loaded( audio_clip
*clip
)
1094 if( clip
->data
&& clip
->size
)
1098 vg_fatal_exit_loop( "Must load audio clip before playing! \n" );
1105 VG_STATIC
void audio_debug_ui( m4x4f mtx_pv
)
1107 if( !vg_audio
.debug_ui
)
1114 * -----------------------------------------------------------------------
1117 float budget
= ((double)vg_audio
.samples_last
/ 44100.0) * 1000.0;
1118 vg_profile_drawn( (struct vg_profile
*[]){ &vg_prof_audio_decode
,
1119 &vg_prof_audio_mix
}, 2,
1120 budget
, (ui_rect
){ 4, VG_PROFILE_SAMPLE_COUNT
*2 + 8,
1127 vg_uictx
.cursor
[0] = 258;
1128 vg_uictx
.cursor
[1] = VG_PROFILE_SAMPLE_COUNT
*2+8+24+12;
1129 vg_uictx
.cursor
[2] = 150;
1130 vg_uictx
.cursor
[3] = 12;
1132 float mb1
= 1024.0f
*1024.0f
,
1133 usage
= vg_linear_get_cur( vg_audio
.audio_pool
) / mb1
,
1134 total
= vg_linear_get_capacity( vg_audio
.audio_pool
) / mb1
,
1135 percent
= (usage
/total
) * 100.0f
;
1137 snprintf( perf
, 127, "Mem: %.1f/%.1fmb (%.1f%%)\n", usage
, total
, percent
);
1139 ui_text( vg_uictx
.cursor
, perf
, 1, 0 );
1140 vg_uictx
.cursor
[1] += 20;
1142 ui_rect overlap_buffer
[ AUDIO_CHANNELS
];
1143 u32 overlap_length
= 0;
1145 /* Draw audio stack */
1146 for( int i
=0; i
<AUDIO_CHANNELS
; i
++ )
1148 audio_channel
*ch
= &vg_audio
.channels
[i
];
1150 vg_uictx
.cursor
[2] = 400;
1151 vg_uictx
.cursor
[3] = 18;
1155 if( !ch
->allocated
)
1157 ui_fill_rect( vg_uictx
.cursor
, 0x50333333 );
1160 vg_uictx
.cursor
[1] += 1;
1164 const char *formats
[] =
1172 int format_index
= 0;
1174 if( ch
->source
->flags
& AUDIO_FLAG_STEREO
)
1176 else if( ch
->source
->flags
& AUDIO_FLAG_VORBIS
)
1181 snprintf( perf
, 127, "%02d %c%c%cD %s %4.2fv'%s'",
1183 (ch
->editable_state
.relinquished
)? 'r': ' ',
1186 formats
[format_index
],
1187 ch
->editable_state
.volume
,
1190 if( format_index
== 0 )
1192 ui_fill_rect( vg_uictx
.cursor
, 0xa00000ff );
1196 ui_fill_rect( vg_uictx
.cursor
, 0xa0333333 );
1199 vg_uictx
.cursor
[0] += 2;
1200 vg_uictx
.cursor
[1] += 2;
1201 ui_text( vg_uictx
.cursor
, perf
, 1, 0 );
1204 vg_uictx
.cursor
[1] += 1;
1206 if( AUDIO_FLAG_SPACIAL_3D
)
1209 v3_copy( ch
->editable_state
.spacial_falloff
, wpos
);
1212 m4x4_mulv( mtx_pv
, wpos
, wpos
);
1214 if( wpos
[3] > 0.0f
)
1216 v2_muls( wpos
, (1.0f
/wpos
[3]) * 0.5f
, wpos
);
1217 v2_add( wpos
, (v2f
){ 0.5f
, 0.5f
}, wpos
);
1220 wr
[0] = wpos
[0] * vg
.window_x
;
1221 wr
[1] = (1.0f
-wpos
[1]) * vg
.window_y
;
1225 for( int j
=0; j
<12; j
++ )
1228 for( int k
=0; k
<overlap_length
; k
++ )
1230 ui_px
*wk
= overlap_buffer
[k
];
1231 if( ((wr
[0] <= wk
[0]+wk
[2]) && (wr
[0]+wr
[2] >= wk
[0])) &&
1232 ((wr
[1] <= wk
[1]+wk
[3]) && (wr
[1]+wr
[3] >= wk
[1])) )
1245 ui_text( wr
, perf
, 1, 0 );
1247 ui_rect_copy( wr
, overlap_buffer
[ overlap_length
++ ] );
1255 #endif /* VG_AUDIO_H */