From cae71005d53086d85c5458fa140013bea9886714 Mon Sep 17 00:00:00 2001
From: Mike Will <[EMAIL REDACTED]>
Date: Wed, 11 Oct 2023 00:42:19 -0400
Subject: [PATCH] Add a multi-channel example
Similar to `demo`, `demo_multi` writes 10 seconds of audio to
`out.wav`, but it sends all even-numbered voices to the left channel
and all odd-numbered voices to the right channel.
---
demo/CMakeLists.txt | 4 ++
demo/basics_multi.c | 89 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
create mode 100644 demo/basics_multi.c
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt
index 6e18f1e..b4453f7 100644
--- a/demo/CMakeLists.txt
+++ b/demo/CMakeLists.txt
@@ -28,6 +28,10 @@ add_custom_command(TARGET demo_mem
target_link_libraries(demo_mem gme)
+
+add_executable(demo_multi Wave_Writer.cpp basics_multi.c)
+target_link_libraries(demo_multi gme)
+
#
# Testing
#
diff --git a/demo/basics_multi.c b/demo/basics_multi.c
new file mode 100644
index 0000000..7205778
--- /dev/null
+++ b/demo/basics_multi.c
@@ -0,0 +1,89 @@
+/* C example that opens a game music file and records 10 seconds to "out.wav" */
+
+#include "gme/gme.h"
+
+#include "Wave_Writer.h" /* wave_ functions for writing sound file */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void handle_error( const char *str )
+{
+ if ( str )
+ {
+ printf( "Error: %s\n", str ); getchar();
+ exit( EXIT_FAILURE );
+ }
+}
+
+short avg( short *ptr, int n )
+{
+ int sum = 0, i = n;
+ while ( i-- )
+ sum += ptr[i];
+ return sum / n;
+}
+
+int main( int argc, char *argv[] )
+{
+ const char *filename = "test.nsf"; /* Default file to open */
+ if ( argc >= 2 )
+ filename = argv[1];
+
+ int sample_rate = 44100; /* number of samples per second */
+ /* index of track to play (0 = first) */
+ int track = argc >= 3 ? atoi(argv[2]) : 0;
+
+ /* Open music file in new multi-channel emulator */
+ gme_type_t file_type = gme_identify_extension( filename );
+ Music_Emu* emu = gme_new_emu_multi_channel( file_type, sample_rate );
+ handle_error( gme_load_file( emu, filename ) );
+
+ /* Start track */
+ handle_error( gme_start_track( emu, track ) );
+
+ /* Begin writing to wave file */
+ wave_open( sample_rate, "out.wav" );
+ wave_enable_stereo();
+
+ const int frames = 64;
+ const int voices = 8;
+ const int channels = 2;
+ const int buf_size = frames * voices * channels;
+
+ /* Record 10 seconds of track */
+ while ( gme_tell( emu ) < 10 * 1000L )
+ {
+ /* Sample buffer */
+ short buf [buf_size], *in = buf, *out = buf;
+
+ /* Fill sample buffer */
+ handle_error( gme_play( emu, buf_size, buf ) );
+
+ /* Render frames for stereo output by sending
+ even-numbered voices to the left channel, and
+ odd-numbered voices to the right channel */
+ for ( int f = frames; f--; out += channels )
+ {
+ int i = 0;
+ short ch [channels];
+ memset( ch, 0, channels * sizeof( short ) );
+ for ( int v = voices; v--; in += channels )
+ {
+ ch[i] += avg( in, channels );
+ i = ( ++i >= channels ) ? 0 : i;
+ }
+ for ( int c = channels; c--; )
+ out[c] = ch[c];
+ }
+
+ /* Write samples to wave file */
+ wave_write( buf, frames * channels );
+ }
+
+ /* Cleanup */
+ gme_delete( emu );
+ wave_close();
+
+ return 0;
+}