# HG changeset patch # User Mike Pavone # Date 1371430677 25200 # Node ID c3abc4ada43d026212329bd2acd80f173e2172eb # Parent b1bc1947d949be8c28812e75eea3727854689a0e Add support for logging YM2612 channels to WAVE files diff -r b1bc1947d949 -r c3abc4ada43d Makefile --- a/Makefile Sun Jun 16 13:42:13 2013 -0700 +++ b/Makefile Sun Jun 16 17:57:57 2013 -0700 @@ -7,8 +7,8 @@ all : dis trans stateview blastem -blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o - $(CC) -ggdb -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o `pkg-config --libs $(LIBS)` +blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o wave.o + $(CC) -ggdb -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o wave.o `pkg-config --libs $(LIBS)` dis : dis.o 68kinst.o $(CC) -o dis dis.o 68kinst.o diff -r b1bc1947d949 -r c3abc4ada43d blastem.c --- a/blastem.c Sun Jun 16 13:42:13 2013 -0700 +++ b/blastem.c Sun Jun 16 17:57:57 2013 -0700 @@ -1919,6 +1919,7 @@ int width = -1; int height = -1; int debug = 0; + int ym_log = 0; FILE *address_log = NULL; for (int i = 2; i < argc; i++) { if (argv[i][0] == '-') { @@ -1963,6 +1964,9 @@ return 1; } break; + case 'y': + ym_log = 1; + break; default: fprintf(stderr, "Unrecognized switch %s\n", argv[i]); return 1; @@ -1989,7 +1993,7 @@ init_vdp_context(&v_context); ym2612_context y_context; - ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer()); + ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); psg_context p_context; psg_init(&p_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_PSG, render_audio_buffer()); diff -r b1bc1947d949 -r c3abc4ada43d wave.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave.c Sun Jun 16 17:57:57 2013 -0700 @@ -0,0 +1,41 @@ +#include "wave.h" +#include +#include + +int wave_init(FILE * f, uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels) +{ + wave_header header; + memcpy(header.chunk.id, "RIFF", 4); + memcpy(header.chunk.format, "WAVE", 4); + header.chunk.size = 0; //This will be filled in later + memcpy(header.format_header.id, "fmt ", 4); + header.format_header.size = sizeof(wave_header) - (sizeof(header.chunk) + sizeof(header.data_header) + sizeof(header.format_header)); + header.audio_format = 1; + header.num_channels = num_channels; + header.sample_rate = sample_rate; + header.byte_rate = sample_rate * num_channels * (bits_per_sample/8); + header.block_align = num_channels * (bits_per_sample/8); + header.bits_per_sample = bits_per_sample; + memcpy(header.data_header.id, "data", 4); + header.data_header.size = 0;//This will be filled in later; + return fwrite(&header, 1, sizeof(header), f) == sizeof(header); +} + +int wave_finalize(FILE * f) +{ + uint32_t size = ftell(f); + fseek(f, offsetof(wave_header, chunk.size), SEEK_SET); + size -= 8; + if (fwrite(&size, sizeof(size), 1, f) != sizeof(size)) { + fclose(f); + return 0; + } + fseek(f, offsetof(wave_header, data_header.size), SEEK_SET); + size -= 36; + if (fwrite(&size, sizeof(size), 1, f)) { + fclose(f); + return 0; + } + fclose(f); + return 1; +} diff -r b1bc1947d949 -r c3abc4ada43d wave.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave.h Sun Jun 16 17:57:57 2013 -0700 @@ -0,0 +1,38 @@ +#ifndef WAVE_H_ +#define WAVE_H_ + +#include +#include + +#pragma pack(push, 1) + +typedef struct { + char id[4]; + uint32_t size; + char format[4]; +} riff_chunk; + +typedef struct { + char id[4]; + uint32_t size; +} riff_sub_chunk; + +typedef struct { + riff_chunk chunk; + riff_sub_chunk format_header; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + riff_sub_chunk data_header; +} wave_header; + +#pragma pack(pop) + +int wave_init(FILE * f, uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels); +int wave_finalize(FILE * f); + +#endif //WAVE_H_ + diff -r b1bc1947d949 -r c3abc4ada43d ym2612.c --- a/ym2612.c Sun Jun 16 13:42:13 2013 -0700 +++ b/ym2612.c Sun Jun 16 17:57:57 2013 -0700 @@ -4,6 +4,7 @@ #include #include "ym2612.h" #include "render.h" +#include "wave.h" //#define DO_DEBUG_PRINT #ifdef DO_DEBUG_PRINT @@ -97,7 +98,18 @@ FILE * debug_file = NULL; uint32_t first_key_on=0; -void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit) +ym2612_context * log_context = NULL; + +void ym_finalize_log() +{ + for (int i = 0; i < NUM_CHANNELS; i++) { + if (log_context->channels[i].logfile) { + wave_finalize(log_context->channels[i].logfile); + } + } +} + +void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options) { dfopen(debug_file, "ym_debug.txt", "w"); memset(context, 0, sizeof(*context)); @@ -114,6 +126,23 @@ //some games seem to expect that the LR flags start out as 1 for (int i = 0; i < NUM_CHANNELS; i++) { context->channels[i].lr = 0xC0; + if (options & YM_OPT_WAVE_LOG) { + char fname[64]; + sprintf(fname, "ym_channel_%d.wav", i); + FILE * f = context->channels[i].logfile = fopen(fname, "wb"); + if (!f) { + fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname); + continue; + } + if (!wave_init(f, sample_rate, 16, 1)) { + fclose(f); + context->channels[i].logfile = NULL; + } + } + } + if (options & YM_OPT_WAVE_LOG) { + log_context = context; + atexit(ym_finalize_log); } if (!did_tbl_init) { //populate sine table @@ -372,6 +401,9 @@ if (value & 0x2000) { value |= 0xC000; } + if (context->channels[i].logfile) { + fwrite(&value, sizeof(value), 1, context->channels[i].logfile); + } if (context->channels[i].lr & 0x80) { context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; } diff -r b1bc1947d949 -r c3abc4ada43d ym2612.h --- a/ym2612.h Sun Jun 16 13:42:13 2013 -0700 +++ b/ym2612.h Sun Jun 16 17:57:57 2013 -0700 @@ -2,11 +2,14 @@ #define YM2612_H_ #include +#include #define NUM_PART_REGS (0xB7-0x30) #define NUM_CHANNELS 6 #define NUM_OPERATORS (4*NUM_CHANNELS) +#define YM_OPT_WAVE_LOG 1 + typedef struct { uint32_t phase_inc; uint32_t phase_counter; @@ -22,6 +25,7 @@ } ym_operator; typedef struct { + FILE * logfile; uint16_t fnum; int16_t output; uint8_t block_fnum_latch; @@ -70,7 +74,7 @@ uint8_t selected_part; } ym2612_context; -void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit); +void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options); void ym_run(ym2612_context * context, uint32_t to_cycle); void ym_address_write_part1(ym2612_context * context, uint8_t address); void ym_address_write_part2(ym2612_context * context, uint8_t address);