Mercurial > hg > dmlib
annotate testpl.c @ 49:033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
8bit, but samples are internally upconverted to 16bit after module loading.)
Also prepare for floating point mixing support.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 01 Oct 2012 02:51:41 +0300 |
parents | fc097f7717df |
children | e0e470c3fc8e |
rev | line source |
---|---|
0 | 1 #include "jss.h" |
2 #include "jssmod.h" | |
3 #include "jssmix.h" | |
4 #include "jssplr.h" | |
5 #include <errno.h> | |
6 #include <string.h> | |
7 #include <unistd.h> | |
8 #include <SDL.h> | |
9 | |
10 | |
11 static const char patNoteTable[12][3] = | |
12 { | |
13 "C-", "C#", "D-", | |
14 "D#", "E-", "F-", | |
15 "F#", "G-", "G#", | |
16 "A-", "A#", "B-" | |
17 }; | |
18 | |
19 | |
20 #define jmpNMODEffectTable (36) | |
21 static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
22 | |
23 | |
24 void printRow(FILE * f, JSSPattern * p, int row) | |
25 { | |
26 int j, k; | |
27 char c; | |
28 JSSNote *n; | |
29 | |
30 if (!p) | |
31 return; | |
32 | |
33 n = &(p->data[p->nchannels * row]); | |
34 | |
35 fprintf(f, "%.2x: ", row); | |
36 | |
37 k = p->nchannels < 5 ? p->nchannels : 5; | |
38 | |
39 for (j = 0; j < k; j++) | |
40 { | |
41 switch (n->note) | |
42 { | |
43 case jsetNotSet: | |
44 fprintf(f, "... "); | |
45 break; | |
46 case jsetNoteOff: | |
47 fprintf(f, "=== "); | |
48 break; | |
49 default: | |
50 fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); | |
51 break; | |
52 } | |
53 | |
54 if (n->instrument != jsetNotSet) | |
55 fprintf(f, "%.2x ", n->instrument + 1); | |
56 else | |
57 fprintf(f, ".. "); | |
58 | |
59 if (n->volume == jsetNotSet) | |
60 fprintf(f, ".. "); | |
61 else if (n->volume >= 0x00 && n->volume <= 0x40) | |
62 fprintf(f, "%.2x ", n->volume); | |
63 else | |
64 { | |
65 switch (n->volume & 0xf0) | |
66 { | |
67 case 0x50: c = '-'; break; | |
68 case 0x60: c = '+'; break; | |
69 case 0x70: c = '/'; break; | |
70 case 0x80: c = '\\'; break; | |
71 case 0x90: c = 'S'; break; | |
72 case 0xa0: c = 'V'; break; | |
73 case 0xb0: c = 'P'; break; | |
74 case 0xc0: c = '<'; break; | |
75 case 0xd0: c = '>'; break; | |
76 case 0xe0: c = 'M'; break; | |
77 default: c = '?'; break; | |
78 } | |
79 fprintf(f, "%c%x ", c, (n->volume & 0x0f)); | |
80 } | |
81 | |
82 if (n->effect >= 0 && n->effect < jmpNMODEffectTable) | |
83 fprintf(f, "%c", jmpMODEffectTable[n->effect]); | |
84 else if (n->effect == jsetNotSet) | |
85 fprintf(f, "."); | |
86 else | |
87 fprintf(f, "?"); | |
88 | |
89 if (n->param != jsetNotSet) | |
90 fprintf(f, "%.2x|", n->param); | |
91 else | |
92 fprintf(f, "..|"); | |
93 | |
94 n++; | |
95 } | |
96 } | |
97 | |
98 | |
99 void audioCallback(void *userdata, Uint8 *stream, int len) | |
100 { | |
101 JSSMixer *d = (JSSMixer *) userdata; | |
102 | |
103 if (d != NULL) | |
104 { | |
105 jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); | |
106 } | |
107 } | |
108 | |
109 | |
110 int main(int argc, char *argv[]) | |
111 { | |
112 SDL_AudioSpec *a_desired, *a_obtained; | |
113 DMResource *inFile; | |
114 char *sname = NULL; | |
115 int result = -1; | |
116 JSSModule *m; | |
117 JSSMixer *d; | |
118 JSSPlayer *p; | |
119 int buflen = 4096; | |
120 | |
121 if (argc > 1) | |
122 sname = argv[1]; | |
123 | |
124 // Open the files | |
125 if (sname == NULL) | |
126 inFile = dmf_create_stdio_stream(stdin); | |
127 else if ((inFile = dmf_create_stdio(sname)) == NULL) | |
128 { | |
129 fprintf(stderr, "Error opening input file '%s'. (%s)\n", sname, strerror(errno)); | |
130 return 1; | |
131 } | |
132 | |
133 // Initialize miniJSS | |
134 fprintf(stderr, "Initializing miniJSS\n"); | |
135 jssInit(); | |
136 | |
137 | |
138 // Read module file | |
139 fprintf(stderr, "Reading file: %s\n", sname); | |
140 #ifdef JSS_SUP_XM | |
141 fprintf(stderr, "* Trying XM...\n"); | |
142 result = jssLoadXM(inFile, &m); | |
143 #endif | |
144 #ifdef JSS_SUP_JSSMOD | |
145 if (result != 0) | |
146 { | |
8
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
147 size_t bufgot, bufsize = dmfsize(inFile); |
0 | 148 Uint8 *buf = dmMalloc(bufsize); |
8
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
149 dmfseek(inFile, 0L, SEEK_SET); |
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
150 fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); |
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
151 if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize) |
0 | 152 { |
8
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
153 fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", |
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
154 bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile))); |
0 | 155 return 2; |
156 } | |
157 result = jssLoadJSSMOD(buf, bufsize, &m); | |
158 dmFree(buf); | |
159 } | |
160 #endif | |
161 dmf_close(inFile); | |
162 | |
8
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
163 if (result != DMERR_OK) |
0 | 164 { |
8
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
165 fprintf(stderr, "Error loading module file, %d: %s\n", |
fc097f7717df
Fix JSSMod loading in viewmod and testpl.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
166 result, dmErrorStr(result)); |
0 | 167 return 3; |
168 } | |
169 | |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
170 // Try to convert it |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
171 if ((result = jssConvertModuleForPlaying(m)) != DMERR_OK) |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
172 { |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
173 fprintf(stderr, "Could not convert module for playing, %d: %s\n", |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
174 result, dmErrorStr(result)); |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
175 return 3; |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
176 } |
0 | 177 |
178 // Initialize SDL audio | |
179 fprintf(stderr, "Pre-initializing params\n"); | |
180 a_desired = dmMalloc(sizeof(SDL_AudioSpec)); | |
181 a_obtained = dmMalloc(sizeof(SDL_AudioSpec)); | |
182 if (!a_desired || !a_obtained) | |
183 { | |
184 fprintf(stderr, "Could not allocate SDL shit\n"); | |
185 return 3; | |
186 } | |
187 | |
188 a_desired->freq = 48000; | |
189 a_desired->format = AUDIO_S16SYS; | |
190 a_desired->channels = 2; | |
191 | |
192 // Initialize mixing device | |
193 fprintf(stderr, "Initializing miniJSS mixer with: %d, %d, %d\n", | |
194 JSS_AUDIO_S16, a_desired->channels, a_desired->freq); | |
195 | |
196 d = jvmInit(JSS_AUDIO_S16, a_desired->channels, a_desired->freq, JMIX_AUTO); | |
197 if (!d) { | |
198 fprintf(stderr, "jvmInit() returned NULL\n"); | |
199 return 3; | |
200 } | |
201 | |
202 a_desired->samples = buflen; | |
203 a_desired->callback = audioCallback; | |
204 a_desired->userdata = (void *) d; | |
205 | |
206 // Open the audio device | |
207 fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n", | |
208 a_desired->format, a_desired->channels, a_desired->freq); | |
209 | |
210 if (SDL_OpenAudio(a_desired, a_obtained) < 0) | |
211 { | |
212 fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); | |
213 return 4; | |
214 } | |
215 | |
216 fprintf(stderr, "Got: %d, %d, %d\n", | |
217 a_obtained->format, a_obtained->channels, a_obtained->freq); | |
218 | |
219 if ((a_obtained->format != a_desired->format) || | |
220 (a_obtained->channels != a_desired->channels) || | |
221 (a_obtained->freq != a_desired->freq)) | |
222 { | |
223 fprintf(stderr, "Could not get wanted audio parameters from SDL!\n"); | |
224 return 8; | |
225 } | |
226 | |
227 free(a_desired); | |
228 | |
229 // Initialize player | |
230 p = jmpInit(d); | |
231 if (!p) | |
232 { | |
233 fprintf(stderr, "jmpInit() returned NULL\n"); | |
234 return 4; | |
235 } | |
236 | |
237 // Set callback | |
238 jvmSetCallback(d, jmpExec, p); | |
239 | |
240 // Initialize playing | |
241 jmpSetModule(p, m); | |
242 jmpPlayOrder(p, 0); | |
243 jvmSetGlobalVol(d, 60); | |
244 | |
245 // okay, main loop here ... "play" module and print out info | |
246 printf("----------------------------------------------------\n"); | |
247 SDL_PauseAudio(0); | |
248 while (p->isPlaying) | |
249 { | |
250 int r = p->iRow; | |
251 while (r == p->iRow && p->isPlaying) | |
252 SDL_Delay(50); | |
253 | |
254 printRow(stdout, p->pPattern, p->iRow); | |
255 printf("\n"); | |
256 } | |
257 | |
258 printf("----------------------------------------------------\n"); | |
259 | |
260 // Free module data | |
261 jmpClose(p); | |
262 jvmClose(d); | |
263 jssFreeModule(m); | |
264 m = NULL; | |
265 | |
266 return 0; | |
267 } |