Skip to content

Commit 4378ca7

Browse files
committed
Initial export code to SBI file format
1 parent 7741a01 commit 4378ca7

File tree

6 files changed

+122
-0
lines changed

6 files changed

+122
-0
lines changed

src/GNUmakefile

+2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,10 @@ OBJS = \
7676
fs/vfs.o \
7777
fs/wad_dir.o \
7878
fs/wad_file.o \
79+
genmidi/actions.o \
7980
genmidi/genmidi.o \
8081
genmidi/genmidi_dir.o \
82+
genmidi/sbi_file.o \
8183
pager/help.o \
8284
pager/hexdump.o \
8385
pager/pager.o \

src/browser/browser.c

+1
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ static const struct action *pal_actions[] = {
219219
static const struct action *opl_actions[] = {
220220
&parent_dir_action,
221221
&view_action,
222+
&genmidi_export_action,
222223
NULL,
223224
};
224225

src/genmidi/actions.c

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// Copyright(C) 2025 Simon Howard
3+
//
4+
// You can redistribute and/or modify this program under the terms of
5+
// the GNU General Public License version 2 as published by the Free
6+
// Software Foundation, or any later version. This program is
7+
// distributed WITHOUT ANY WARRANTY; without even the implied warranty
8+
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
//
10+
11+
#include <assert.h>
12+
#include <ncurses.h>
13+
14+
#include "browser/browser.h"
15+
#include "browser/directory_pane.h"
16+
#include "common.h"
17+
#include "fs/vfile.h"
18+
#include "genmidi/genmidi.h"
19+
#include "ui/actions_bar.h"
20+
21+
static void ActionExportVoice(void)
22+
{
23+
struct genmidi_bank *bank = GENMIDI_DirGetBank(active_pane->dir);
24+
struct genmidi_instrument *instr;
25+
int selected = B_DirectoryPaneSelected(active_pane);
26+
VFILE *out;
27+
28+
if (selected < 0) {
29+
return;
30+
}
31+
32+
instr = &bank->instrs[selected / 2];
33+
34+
// TODO: Write to the correct directory
35+
out = vfwrapfile(fopen("foo.sbi", "wb"));
36+
GENMIDI_WriteSBI(instr, (selected % 2) != 0, out);
37+
vfclose(out);
38+
}
39+
40+
const struct action genmidi_export_action = {
41+
KEY_F(5), 'C', "Export", "> Export", ActionExportVoice,
42+
};

src/genmidi/genmidi.h

+5
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,19 @@ struct genmidi_bank {
5656
struct genmidi_instrument instrs[NUM_GENMIDI_INSTRS];
5757
};
5858

59+
struct action;
5960
struct directory_entry;
6061
struct file_type;
6162

6263
extern const struct file_type file_type_genmidi_bank;
6364
extern const struct file_type file_type_genmidi_voice;
65+
extern const struct action genmidi_export_action;
6466

6567
bool GENMIDI_LoadBank(struct genmidi_bank *bank, VFILE *in);
6668
struct directory *GENMIDI_OpenDir(struct directory *parent,
6769
struct directory_entry *ent);
70+
struct genmidi_bank *GENMIDI_DirGetBank(struct directory *dir);
71+
bool GENMIDI_WriteSBI(struct genmidi_instrument *instr, bool voice2,
72+
VFILE *out);
6873

6974
#endif /* #ifndef GENMIDI__GENMIDI_H_INCLUDED */

src/genmidi/genmidi_dir.c

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ struct genmidi_dir {
2626
const struct file_type file_type_genmidi_bank = {"GENMIDI bank"};
2727
const struct file_type file_type_genmidi_voice = {"Voice"};
2828

29+
struct genmidi_bank *GENMIDI_DirGetBank(struct directory *_dir)
30+
{
31+
struct genmidi_dir *dir = (struct genmidi_dir *) _dir;
32+
return &dir->bank;
33+
}
34+
2935
static const char *InstrumentNumber(int index)
3036
{
3137
static char buf[8];

src/genmidi/sbi_file.c

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//
2+
// Copyright(C) 2025 Simon Howard
3+
//
4+
// You can redistribute and/or modify this program under the terms of
5+
// the GNU General Public License version 2 as published by the Free
6+
// Software Foundation, or any later version. This program is
7+
// distributed WITHOUT ANY WARRANTY; without even the implied warranty
8+
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9+
//
10+
11+
#include <assert.h>
12+
#include <ncurses.h>
13+
14+
#include "common.h"
15+
#include "fs/vfile.h"
16+
#include "genmidi/genmidi.h"
17+
18+
#define HEADER_VALUE "SBI\x1a"
19+
20+
static const int sbi_field_mapping[] = {
21+
INSTR_M_AM_VIBRATO_EG, // 0
22+
INSTR_C_AM_VIBRATO_EG, // 1
23+
INSTR_M_KSL, // 2 ; _VOLUME is |ed in below
24+
INSTR_C_KSL, // 3 ; _VOLUME is |ed in below
25+
INSTR_M_ATTACK_DECAY, // 4
26+
INSTR_C_ATTACK_DECAY, // 5
27+
INSTR_M_SUSTAIN_RELEASE, // 6
28+
INSTR_C_SUSTAIN_RELEASE, // 7
29+
INSTR_M_WAVEFORM, // 8
30+
INSTR_C_WAVEFORM, // 9
31+
INSTR_FEEDBACK_FM, // 10
32+
};
33+
34+
bool GENMIDI_WriteSBI(struct genmidi_instrument *instr, bool voice2, VFILE *out)
35+
{
36+
uint8_t *voicedata;
37+
uint8_t buf[16];
38+
int i;
39+
40+
if (vfwrite(HEADER_VALUE, 4, 1, out) != 1 ||
41+
vfwrite(instr->name, 32, 1, out) != 1) {
42+
return false;
43+
}
44+
45+
if (voice2) {
46+
voicedata = instr->voice2;
47+
} else {
48+
voicedata = instr->voice1;
49+
}
50+
51+
memset(buf, 0, sizeof(buf));
52+
for (i = 0; i < arrlen(sbi_field_mapping); ++i) {
53+
buf[i] = voicedata[sbi_field_mapping[i]];
54+
}
55+
56+
buf[2] |= voicedata[INSTR_M_VOLUME];
57+
buf[3] |= voicedata[INSTR_C_VOLUME];
58+
buf[12] = voicedata[INSTR_NOTE_OFFSET];
59+
60+
if ((instr->hdr.flags & GENMIDI_FLAG_FIXED) != 0) {
61+
buf[11] = 1;
62+
buf[13] = instr->hdr.fixed_note;
63+
}
64+
65+
return vfwrite(buf, 16, 1, out) == 1;
66+
}

0 commit comments

Comments
 (0)