Skip to content

Commit

Permalink
Merge pull request #49 from ChrisBlueStone/record-audio
Browse files Browse the repository at this point in the history
Added WAV capturing option
  • Loading branch information
ChrisBlueStone committed Jul 19, 2023
2 parents a0d99c7 + 7cc1071 commit c6e28f7
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 22 deletions.
7 changes: 5 additions & 2 deletions src/bgmlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "ebmusv2.h"
#include "id.h"

#define IDC_ROM_FILE 17
#define IDC_ORIG_ROM_FILE 18
Expand Down Expand Up @@ -121,8 +122,10 @@ void load_instruments() {
sample_ptr_base = 0x6C00;
decode_samples(&spc[sample_ptr_base]);
inst_base = 0x6E00;
if (samp[0].data == NULL)
song_playing = FALSE;
if (samp[0].data == NULL) {
stop_playing();
EnableMenuItem(hmenu, ID_PLAY, MF_ENABLED);
}
initialize_state();
}

Expand Down
15 changes: 14 additions & 1 deletion src/ebmusv2.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#ifndef EBMUSV2_H
#define EBMUSV2_H

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "structs.h"

Expand Down Expand Up @@ -45,6 +49,7 @@ extern HWND tab_hwnd[NUM_TABS];
#define hwndInstruments tab_hwnd[1]
#define hwndEditor tab_hwnd[2]
#define hwndPackList tab_hwnd[3]
char *open_dialog(BOOL (WINAPI *func)(LPOPENFILENAME), char *filter, char *extension, DWORD flags);
BOOL get_original_rom(void);
BOOL save_all_packs(void);

Expand Down Expand Up @@ -151,6 +156,7 @@ void free_metadata(void);

// misc.c
void enable_menu_items(const BYTE *list, int flags);
void update_menu_item(UINT item, LPTSTR label);
#ifdef CreateWindow
void set_up_hdc(HDC hdc);
void reset_hdc(HDC hdc);
Expand Down Expand Up @@ -223,7 +229,12 @@ void order_delete(int pos);
// sound.c
extern int mixrate;
extern int chmask;
extern BOOL song_playing;
BOOL is_playing(void);
BOOL start_playing(void);
void stop_playing(void);
BOOL is_capturing_audio(void);
BOOL start_capturing_audio(void);
void stop_capturing_audio(void);
extern int timer_speed;
int sound_init(void);
void winmm_message(unsigned int uMsg);
Expand All @@ -246,3 +257,5 @@ void editor_command(int id);
#endif
void format_status(int part, const char* format, ...);
void set_tracker_status(int part, BYTE *code);

#endif // EBMUSV2_H
3 changes: 2 additions & 1 deletion src/id.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
#define ID_OPTIONS 130
#define ID_PLAY 131
#define ID_STOP 132
#define ID_CLEAR_SONG 133
#define ID_CAPTURE_AUDIO 133
#define ID_CLEAR_SONG 134
#define ID_ZOOM_IN 140
#define ID_ZOOM_OUT 141
#define ID_STATUS_BAR 142
Expand Down
9 changes: 6 additions & 3 deletions src/inst.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <windows.h>
#include <mmsystem.h>
#include <commctrl.h>
#include "id.h"
#include "ebmusv2.h"

#define IDC_SAMPLIST_CAPTION 1
Expand Down Expand Up @@ -225,8 +226,7 @@ LRESULT CALLBACK InstrumentsWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
SendMessage(instlist, LB_ADDSTRING, 0, (LPARAM)buf);
*p++ = i;
}
if (sound_init())
song_playing = TRUE;
start_playing();
timer_speed = 0;
memset(&state.chan, 0, sizeof state.chan);
for (int ch = 0; ch < 8; ch++) {
Expand Down Expand Up @@ -255,6 +255,7 @@ LRESULT CALLBACK InstrumentsWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
closeMidiInDevice();
openMidiInDevice(midiDevice, MidiInProc);

EnableMenuItem(hmenu, ID_STOP, MF_GRAYED);
break;
}
case WM_COMMAND: {
Expand Down Expand Up @@ -288,14 +289,16 @@ LRESULT CALLBACK InstrumentsWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
move_controls(hWnd, &inst_list_template, lParam);
break;
case WM_DESTROY:
song_playing = FALSE;
stop_playing();
state = pattop_state;
timer_speed = 500;
chmask = prev_chmask;
closeMidiInDevice();

// Store the current selected instrument.
selectedInstrument = SendMessage(instlist, LB_GETCURSEL, 0, 0);

EnableMenuItem(hmenu, ID_PLAY, MF_ENABLED);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
Expand Down
2 changes: 1 addition & 1 deletion src/loadrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ BOOL close_rom() {
// This protects from crashes if an SPC was playing.
free_samples();
free_song(&cur_song);
song_playing = FALSE;
stop_playing();
initialize_state();

memset(packs_loaded, 0xFF, 3);
Expand Down
51 changes: 42 additions & 9 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ HWND hwndStatus;
HMENU hmenu, hcontextmenu;
HWND tab_hwnd[NUM_TABS];

static const int INST_TAB = 1;
static int current_tab;
static const char *const tab_class[NUM_TABS] = {
"ebmused_bgmlist",
Expand All @@ -68,10 +69,9 @@ static const WNDPROC tab_wndproc[NUM_TABS] = {
PackListWndProc,
};


static char filename[MAX_PATH];
static OPENFILENAME ofn;
static char *open_dialog(BOOL (WINAPI *func)(LPOPENFILENAME),
char *open_dialog(BOOL (WINAPI *func)(LPOPENFILENAME),
char *filter, char *extension, DWORD flags)
{
*filename = '\0';
Expand Down Expand Up @@ -593,6 +593,18 @@ BOOL save_all_packs() {
return success;
}

static BOOL validate_playable(void) {
if (cur_song.order_length == 0) {
MessageBox2("No song loaded", "Play", MB_ICONEXCLAMATION);
return FALSE;
} else if (samp[0].data == NULL) {
MessageBox2("No instruments loaded", "Play", MB_ICONEXCLAMATION);
return FALSE;
} else {
return TRUE;
}
}

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case 0x3BB: case 0x3BC: case 0x3BD: // MM_WOM_OPEN, CLOSE, DONE
Expand Down Expand Up @@ -672,17 +684,38 @@ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
editor_command(id);
break;
case ID_PLAY:
if (cur_song.order_length == 0)
MessageBox2("No song loaded", "Play", MB_ICONEXCLAMATION);
else if (samp[0].data == NULL)
MessageBox2("No instruments loaded", "Play", MB_ICONEXCLAMATION);
else {
if (sound_init()) song_playing = TRUE;
if (validate_playable()) {
start_playing();
EnableMenuItem(hmenu, ID_STOP, MF_ENABLED);
}
break;
case ID_STOP:
song_playing = FALSE;
if (current_tab == INST_TAB) {
stop_capturing_audio();
} else {
stop_playing();
EnableMenuItem(hmenu, ID_PLAY, MF_ENABLED);
}
break;
case ID_CAPTURE_AUDIO: {
if (current_tab == INST_TAB) {
if (is_capturing_audio()) {
stop_capturing_audio();
} else {
start_capturing_audio();
}
} else {
if (is_capturing_audio()) {
stop_capturing_audio();
} else {
if (validate_playable() && start_capturing_audio()) {
start_playing();
EnableMenuItem(hmenu, ID_STOP, MF_ENABLED);
}
}
}
break;
}
case ID_OCTAVE_1: case ID_OCTAVE_1+1: case ID_OCTAVE_1+2:
case ID_OCTAVE_1+3: case ID_OCTAVE_1+4:
octave = id - ID_OCTAVE_1;
Expand Down
8 changes: 8 additions & 0 deletions src/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ void enable_menu_items(const BYTE *list, int flags) {
while (*list) EnableMenuItem(hmenu, *list++, flags);
}

void update_menu_item(UINT item, LPTSTR label) {
MENUITEMINFO menuiteminfo = { sizeof(MENUITEMINFO) };
GetMenuItemInfo(hmenu, item, FALSE, &menuiteminfo);
menuiteminfo.fMask = MIIM_STRING;
menuiteminfo.dwTypeData = label;
SetMenuItemInfo(hmenu, item, FALSE, &menuiteminfo);
}

HFONT oldfont;
COLORREF oldtxt, oldbk;

Expand Down
9 changes: 6 additions & 3 deletions src/play.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdio.h>
#include <string.h>
#include "ebmusv2.h"
#include "id.h"

BYTE spc[65536];
int inst_base = 0x6E00;
Expand Down Expand Up @@ -315,7 +316,8 @@ void load_pattern() {
state.repeat_count = cur_song.repeat;
if (state.repeat_count == 0) {
state.ordnum--;
song_playing = FALSE;
stop_playing();
EnableMenuItem(hmenu, ID_PLAY, MF_ENABLED);
return;
}
state.ordnum = cur_song.repeat_pos;
Expand Down Expand Up @@ -512,7 +514,7 @@ BOOL do_timer() {
state.cycle_timer -= 256;
while (!do_cycle(&state)) {
load_pattern();
if (!song_playing) return FALSE;
if (!is_playing()) return FALSE;
load_pattern_into_tracker();
}
} else {
Expand All @@ -539,6 +541,7 @@ void initialize_state() {
load_pattern();
} else {
pattop_state = state;
song_playing = FALSE;
stop_playing();
EnableMenuItem(hmenu, ID_PLAY, MF_ENABLED);
}
}
3 changes: 2 additions & 1 deletion src/resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ BEGIN
POPUP "&Song"
BEGIN
MENUITEM "&Play\tCtrl+P", ID_PLAY
MENUITEM "&Stop\tEsc", ID_STOP
MENUITEM "&Stop\tEsc", ID_STOP, GRAYED
MENUITEM "Capture &Audio...", ID_CAPTURE_AUDIO
MENUITEM SEPARATOR
MENUITEM "&Clear", ID_CLEAR_SONG, GRAYED
END
Expand Down
84 changes: 83 additions & 1 deletion src/sound.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commdlg.h>
#include <mmsystem.h>
#include "id.h"
#include "ebmusv2.h"
Expand All @@ -11,7 +12,23 @@ int bufsize = 2205;
int chmask = 255;
int timer_speed = 500;
HWAVEOUT hwo;
BOOL song_playing;
static BOOL song_playing = FALSE;
FILE* wav_file = NULL;

BOOL is_playing(void) { return song_playing; }
BOOL start_playing(void) {
if (sound_init()) {
song_playing = TRUE;
EnableMenuItem(hmenu, ID_PLAY, MF_GRAYED);
}

return song_playing;
}
void stop_playing(void) {
stop_capturing_audio();
song_playing = FALSE;
EnableMenuItem(hmenu, ID_STOP, MF_GRAYED);
}

static WAVEHDR wh[2], *curbuf = &wh[0];
static int bufs_used;
Expand Down Expand Up @@ -46,9 +63,70 @@ int sound_init() {
wh[1].dwBufferLength = bufsize*4;
waveOutPrepareHeader(hwo, &wh[0], sizeof *wh);
waveOutPrepareHeader(hwo, &wh[1], sizeof *wh);

return 1;
}

BOOL is_capturing_audio(void) {
return wav_file ? TRUE : FALSE;
}

BOOL start_capturing_audio(void) {
if (song_playing || sound_init()) {
char *file = open_dialog(GetSaveFileName, "WAV files (*.wav)\0*.wav\0", "wav", OFN_OVERWRITEPROMPT);
if (file) {
stop_capturing_audio();
wav_file = fopen(file, "wb");

if (wav_file) {
update_menu_item(ID_CAPTURE_AUDIO, "Stop C&apturing");
EnableMenuItem(hmenu, ID_STOP, MF_ENABLED);

DWORD size_placeholder = 0;
DWORD format_header_size = 16;
WORD formatTag = WAVE_FORMAT_PCM;
WORD num_channels = 2;
DWORD sample_rate = mixrate;
DWORD avg_byte_rate = mixrate*4;
WORD block_alignment = 4;
WORD bit_depth = 16;

fputs("RIFF", wav_file);
fwrite(&size_placeholder, sizeof size_placeholder, 1, wav_file);
fputs("WAVE", wav_file);
fputs("fmt ", wav_file);
fwrite(&format_header_size, sizeof format_header_size, 1, wav_file);
fwrite(&formatTag, sizeof formatTag, 1, wav_file);
fwrite(&num_channels, sizeof num_channels, 1, wav_file);
fwrite(&sample_rate, sizeof sample_rate, 1, wav_file);
fwrite(&avg_byte_rate, sizeof avg_byte_rate, 1, wav_file);
fwrite(&block_alignment, sizeof block_alignment, 1, wav_file);
fwrite(&bit_depth, sizeof bit_depth, 1, wav_file);
fputs("data", wav_file);
fwrite(&size_placeholder, sizeof size_placeholder, 1, wav_file);
}
}
}

return wav_file ? TRUE : FALSE;
}

void stop_capturing_audio(void) {
if (wav_file) {
update_menu_item(ID_CAPTURE_AUDIO, "Capture &Audio...");

int size = ftell(wav_file) - 8;
fseek(wav_file, 4, SEEK_SET);
fwrite(&size, sizeof size, 1, wav_file);

fseek(wav_file, 40, SEEK_SET);
size -= 36;
fwrite(&size, sizeof size, 1, wav_file);
fclose(wav_file);
wav_file = NULL;
}
}

static void sound_uninit() {
waveOutUnprepareHeader(hwo, &wh[0], sizeof *wh);
waveOutUnprepareHeader(hwo, &wh[1], sizeof *wh);
Expand Down Expand Up @@ -232,6 +310,10 @@ static void fill_buffer() {
putchar(219);
putchar('\n');
}*/
if (wav_file) {
fwrite(curbuf->lpData, curbuf->dwBufferLength, 1, wav_file);
}

waveOutWrite(hwo, curbuf, sizeof *wh);
bufs_used++;
curbuf = &wh[(curbuf - wh) ^ 1];
Expand Down

0 comments on commit c6e28f7

Please sign in to comment.