-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathloadsf2.c
139 lines (129 loc) · 4.28 KB
/
loadsf2.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* loadsf2.c - load/split a sf2 riff file into component chunks
*
* Copyright 2015 Nathan Laredo (laredo@gnu.org)
*
* This file may be freely distributed under the terms of
* the GNU General Public Licence (GPL).
*
* CFLAGS += -Wno-multichar
*/
#include "SDL2/SDL.h"
#include "SDL2/SDL_audio.h"
#include "soundfont2.h"
#include <stdio.h>
#include <signal.h>
struct sfSFBK sf2; /* pointers to everything loaded go here */
extern int verbose;
/* for each tag value found, describe where to stick a pointer to the data */
struct fillSFBK { char *tag; void *dest; };
struct fillSFBK filldata[] = {
{ "ifil", &sf2.ifil }, { "isng", &sf2.isng }, { "INAM", &sf2.INAM },
{ "irom", &sf2.irom }, { "iver", &sf2.iver }, { "ICRD", &sf2.ICRD },
{ "IENG", &sf2.IENG }, { "IPRD", &sf2.IPRD }, { "ICOP", &sf2.ICOP },
{ "ICMT", &sf2.ICMT }, { "ISFT", &sf2.ISFT }, { "smpl", &sf2.smpl },
{ "sm24", &sf2.sm24 }, { "phdr", &sf2.phdr }, { "pbag", &sf2.pbag },
{ "pmod", &sf2.pmod }, { "pgen", &sf2.pgen }, { "inst", &sf2.inst },
{ "ibag", &sf2.ibag }, { "imod", &sf2.imod }, { "igen", &sf2.igen },
{ "shdr", &sf2.shdr }, { NULL, NULL }
};
static void fill_sf2(Uint32 tag, void *buf, Uint32 size)
{
int i;
for (i = 0; filldata[i].tag != NULL && filldata[i].dest != NULL; i++) {
if (*(Uint32 *)filldata[i].tag == tag) {
memcpy(filldata[i].dest, &buf, sizeof(void *));
memcpy(sizeof(void *) + filldata[i].dest, &size, sizeof(Uint32));
return;
}
}
fprintf(stderr, "Unhandled %.4s in sf2 file.\n", (char *)&tag);
}
static void parse_subchunk(struct riffChunk *parent, Uint32 level)
{
Uint32 offset = 4; /* skip the data tag */
struct riffChunk *buf = (struct riffChunk *)(parent->data + offset);
if (level > 3) {
fprintf(stderr, "ignored unexpectedly deep recursion in RIFF file\n");
return;
}
while (parent->len - offset >= sizeof(struct riffChunk)) {
buf = (struct riffChunk *)(parent->data + offset);
if (0) {
fprintf(stderr, "%*sTAG = %.4s LEN = %d\n", 2 + level * 2, "",
(char *)&buf->tag, buf->len);
}
if (buf->tag == SDL_SwapBE32('LIST')) {
parse_subchunk(buf, level + 1); /* look for chunks inside this chunk */
} else {
fill_sf2(buf->tag, &buf->data, buf->len);
}
offset += sizeof(struct riffChunk) + buf->len;
}
return;
}
/* load soundfont2 riff file into sf2 struct, return pointer to raw riff data */
struct riffChunk *load_sf2(char *filename)
{
SDL_RWops *rw = SDL_RWFromFile(filename, "r");
Uint32 tag, len;
Sint64 size;
struct riffChunk *buf = NULL;
int error = 0;
if (!rw) {
if (verbose)
perror(filename);
return NULL;
}
size = SDL_RWsize(rw);
/* at the top level there should only be one chunk */
/* but loop anyway in case someone concatenated riff files */
while (size >= sizeof(struct riffChunk)) {
tag = SDL_ReadLE32(rw);
len = SDL_ReadLE32(rw);
if (!(buf = malloc(sizeof(struct riffChunk) + len))) {
perror("malloc");
return NULL;
}
buf->tag = tag;
buf->len = len;
if (SDL_RWread(rw, buf->data, len, 1) < 1) {
/* done reading the file, or read in error */
free(buf);
return NULL;
}
if (0) {
fprintf(stderr, "TAG = %.4s LEN = %d\n", (char *)&buf->tag, buf->len);
}
if (*(Uint32 *)buf->data == SDL_SwapBE32('sfbk')) {
parse_subchunk(buf, 0); /* look for chunks inside this chunk */
}
size -= sizeof(struct riffChunk) + buf->len;
};
SDL_RWclose(rw);
if (sf2.phdr_size < sizeof(struct sfPresetHeader) * 2) { error++; }
if (sf2.pbag_size < sizeof(struct sfPresetBag) * 2) { error++; }
if (sf2.pgen_size < sizeof(struct sfGenList) * 2) { error++; }
if (sf2.inst_size < sizeof(struct sfInst) * 2) { error++; }
if (sf2.igen_size < sizeof(struct sfInstGenList) * 2) { error++; }
if (sf2.shdr_size < sizeof(struct sfSample) * 2) { error++; }
if (error) {
fprintf(stderr, "%s: malformed sf2 file, ignoring\n", filename);
memset(&sf2, 0, sizeof(sf2));
free(buf);
return NULL;
}
return buf;
}
#ifdef TEST_TARGET
int verbose = 1;
/* stand alone testing of above file parsing */
int main(int argc, char **argv)
{
if (argc > 1) {
load_sf2(argv[1]);
signal (SIGTRAP, SIG_IGN); // if not debugging, ignore the int3
asm volatile ("int3");
}
exit(0);
}
#endif