# HG changeset patch # User Michael Pavone # Date 1678931424 25200 # Node ID b3832f73444ff4f707e9c2823a60ac8986ff8d1e # Parent c79896ff1a2d50dcaf5824cb0696b8c4f1724810 Save audio to a wave file when saving video to APNG diff -r c79896ff1a2d -r b3832f73444f bindings.c --- a/bindings.c Wed Mar 15 18:49:47 2023 -0700 +++ b/bindings.c Wed Mar 15 18:50:24 2023 -0700 @@ -418,9 +418,12 @@ if (allow_content_binds) { if (render_saving_video()) { render_end_video(); + render_end_audio(); } else { char *path = get_content_config_path("ui\0video_path\0", "ui\0video_template\0", "blastem_%c.apng"); render_save_video(path); + path = get_content_config_path("ui\0audio_path\0", "ui\0audio_template\0", "blastem_%c.wav"); + render_save_audio(path); } } break; diff -r c79896ff1a2d -r b3832f73444f render_audio.c --- a/render_audio.c Wed Mar 15 18:49:47 2023 -0700 +++ b/render_audio.c Wed Mar 15 18:50:24 2023 -0700 @@ -6,6 +6,7 @@ #include "util.h" #include "config.h" #include "blastem.h" +#include "wave.h" static uint8_t output_channels; static uint32_t buffer_samples, sample_rate; @@ -18,6 +19,34 @@ static float overall_gain_mult, *mix_buf; static int sample_size; +static FILE *wav_file; +void render_end_audio(void) +{ + render_lock_audio(); + if (wav_file) { + wave_finalize(wav_file); + fclose(wav_file); + wav_file = NULL; + } + render_unlock_audio(); +} + +void render_save_audio(char *path) +{ + render_end_audio(); + FILE *f = fopen(path, "wb"); + if (f) { + wave_init(f, sample_rate, 16, 2); + render_lock_audio(); + wav_file = f; + render_unlock_audio(); + printf("Saving audio to %s\n", path); + } else { + warning("Failed to open %s for writing\n", path); + } + free(path); +} + typedef void (*conv_func)(float *samples, void *vstream, int sample_count); static void convert_null(float *samples, void *vstream, int sample_count) @@ -41,11 +70,17 @@ } *stream = out_sample; } + if (wav_file) { + fwrite(vstream, sizeof(int16_t), sample_count, wav_file); + } } +static int16_t *wave_buffer; +static int wave_buffer_samples; static void clamp_f32(float *samples, void *vstream, int sample_count) { - for (; sample_count > 0; sample_count--, samples++) + float *start = samples; + for (int cur_count = sample_count; cur_count > 0; cur_count--, samples++) { float sample = *samples; if (sample > 1.0f) { @@ -55,6 +90,16 @@ } *samples = sample; } + if (wav_file) { + if (!wave_buffer) { + wave_buffer = calloc(sample_count, sizeof(int16_t)); + wave_buffer_samples = sample_count; + } else if (sample_count < wave_buffer_samples) { + wave_buffer = realloc(wave_buffer, sizeof(int16_t) * sample_count); + wave_buffer_samples = sample_count; + } + convert_s16(start, wave_buffer, sample_count); + } } static int32_t mix_f32(audio_source *audio, float *stream, int samples) diff -r c79896ff1a2d -r b3832f73444f render_audio.h --- a/render_audio.h Wed Mar 15 18:49:47 2023 -0700 +++ b/render_audio.h Wed Mar 15 18:50:24 2023 -0700 @@ -37,6 +37,8 @@ void render_pause_source(audio_source *src); void render_resume_source(audio_source *src); void render_free_source(audio_source *src); +void render_end_audio(void); +void render_save_audio(char *path); //interface for render backends void render_audio_initialized(render_audio_format format, uint32_t rate, uint8_t channels, uint32_t buffer_size, int sample_size); int mix_and_convert(unsigned char *byte_stream, int len, int *min_remaining_out);