changeset 2304:b3832f73444f

Save audio to a wave file when saving video to APNG
author Michael Pavone <pavone@retrodev.com>
date Wed, 15 Mar 2023 18:50:24 -0700
parents c79896ff1a2d
children 6aca1734d573
files bindings.c render_audio.c render_audio.h
diffstat 3 files changed, 51 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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)
--- 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);