aboutsummaryrefslogtreecommitdiff
path: root/src/midiplay/wave_writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/midiplay/wave_writer.c')
-rwxr-xr-xsrc/midiplay/wave_writer.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/midiplay/wave_writer.c b/src/midiplay/wave_writer.c
new file mode 100755
index 0000000..e2c9611
--- /dev/null
+++ b/src/midiplay/wave_writer.c
@@ -0,0 +1,170 @@
+/* snes_spc 0.9.0. http://www.slack.net/~ant/ */
+
+#include "wave_writer.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef MUSPLAY_USE_WINAPI
+#include <windows.h>
+#endif
+
+/* Copyright (C) 2003-2007 Shay Green. This module is free software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser
+General Public License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version. This
+module is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details. You should have received a copy of the GNU Lesser General Public
+License along with this module; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
+
+enum { buf_size = 32768 * 2 };
+enum { header_size = 0x2C };
+
+typedef short sample_t;
+
+static unsigned char* buf;
+static FILE* file;
+static long sample_count_;
+static long sample_rate_;
+static long buf_pos;
+static int chan_count;
+
+static void exit_with_error( const char* str )
+{
+ fprintf(stderr, "WAVE Writer Error: %s\n", str );
+ fflush(stderr);
+}
+
+int wave_open( long sample_rate, const char* filename )
+{
+ sample_count_ = 0;
+ sample_rate_ = sample_rate;
+ buf_pos = header_size;
+ chan_count = 1;
+
+ buf = (unsigned char*) malloc( buf_size * sizeof *buf );
+ if ( !buf )
+ {
+ exit_with_error( "Out of memory" );
+ return -1;
+ }
+
+#ifndef MUSPLAY_USE_WINAPI
+ file = fopen( filename, "wb" );
+#else
+ wchar_t widePath[MAX_PATH];
+ int size = MultiByteToWideChar(CP_UTF8, 0, filename, strlen(filename), widePath, MAX_PATH);
+ widePath[size] = '\0';
+ file = _wfopen( widePath, L"wb" );
+#endif
+ if (!file)
+ {
+ exit_with_error( "Couldn't open WAVE file for writing" );
+ return -1;
+ }
+
+ setvbuf( file, 0, _IOFBF, 32 * 1024L );
+ return 0;
+}
+
+void wave_enable_stereo( void )
+{
+ chan_count = 2;
+}
+
+static void flush_()
+{
+ if ( buf_pos && !fwrite( buf, (size_t)buf_pos, 1, file ) )
+ exit_with_error( "Couldn't write WAVE data" );
+ buf_pos = 0;
+}
+
+void wave_write( short const* in, long remain )
+{
+ sample_count_ += remain;
+ while ( remain )
+ {
+ if ( buf_pos >= buf_size )
+ flush_();
+
+ {
+ unsigned char* p = &buf [buf_pos];
+ long n = (buf_size - (unsigned long)buf_pos) / sizeof (sample_t);
+ if ( n > remain )
+ n = remain;
+ remain -= n;
+
+ /* convert to LSB first format */
+ while ( n-- )
+ {
+ int s = *in++;
+ *p++ = (unsigned char) s & (0x00FF);
+ *p++ = (unsigned char) (s >> 8) & (0x00FF);
+ }
+
+ buf_pos = p - buf;
+ assert( buf_pos <= buf_size );
+ }
+ }
+}
+
+long wave_sample_count( void )
+{
+ return sample_count_;
+}
+
+static void set_le32( void* p, unsigned long n )
+{
+ ((unsigned char*) p) [0] = (unsigned char) n & (0xFF);
+ ((unsigned char*) p) [1] = (unsigned char) (n >> 8) & (0xFF);
+ ((unsigned char*) p) [2] = (unsigned char) (n >> 16) & (0xFF);
+ ((unsigned char*) p) [3] = (unsigned char) (n >> 24) & (0xFF);
+}
+
+void wave_close( void )
+{
+ if ( file )
+ {
+ /* generate header */
+ unsigned char h [header_size] =
+ {
+ 'R','I','F','F',
+ 0,0,0,0, /* length of rest of file */
+ 'W','A','V','E',
+ 'f','m','t',' ',
+ 0x10,0,0,0, /* size of fmt chunk */
+ 1,0, /* uncompressed format */
+ 0,0, /* channel count */
+ 0,0,0,0, /* sample rate */
+ 0,0,0,0, /* bytes per second */
+ 0,0, /* bytes per sample frame */
+ 16,0, /* bits per sample */
+ 'd','a','t','a',
+ 0,0,0,0, /* size of sample data */
+ /* ... */ /* sample data */
+ };
+ long ds = sample_count_ * (long)sizeof (sample_t);
+ int frame_size = chan_count * (long)sizeof (sample_t);
+
+ set_le32( h + 0x04, header_size - 8 + ds );
+ h [0x16] = (unsigned char)chan_count;
+ set_le32( h + 0x18, (unsigned long)sample_rate_ );
+ set_le32( h + 0x1C, (unsigned long)sample_rate_ * (unsigned long)frame_size );
+ h [0x20] = (unsigned char)frame_size;
+ set_le32( h + 0x28, (unsigned long)ds );
+
+ flush_();
+
+ /* write header */
+ fseek( file, 0, SEEK_SET );
+ fwrite( h, header_size, 1, file );
+ fclose( file );
+ file = 0;
+ free( buf );
+ buf = 0;
+ }
+}