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 {
|
|
147 size_t bufsize = dmfsize(inFile);
|
|
148 Uint8 *buf = dmMalloc(bufsize);
|
|
149 fprintf(stderr, "* Trying JSSMOD...\n");
|
|
150 if (dmfread(buf, 1, bufsize, inFile) != bufsize)
|
|
151 {
|
|
152 fprintf(stderr, "Error reading file!\n");
|
|
153 return 2;
|
|
154 }
|
|
155 result = jssLoadJSSMOD(buf, bufsize, &m);
|
|
156 dmFree(buf);
|
|
157 }
|
|
158 #endif
|
|
159 dmf_close(inFile);
|
|
160
|
|
161 if (result != 0)
|
|
162 {
|
|
163 fprintf(stderr, "Error loading module file: %d\n", result);
|
|
164 return 3;
|
|
165 }
|
|
166
|
|
167
|
|
168 // Initialize SDL audio
|
|
169 fprintf(stderr, "Pre-initializing params\n");
|
|
170 a_desired = dmMalloc(sizeof(SDL_AudioSpec));
|
|
171 a_obtained = dmMalloc(sizeof(SDL_AudioSpec));
|
|
172 if (!a_desired || !a_obtained)
|
|
173 {
|
|
174 fprintf(stderr, "Could not allocate SDL shit\n");
|
|
175 return 3;
|
|
176 }
|
|
177
|
|
178 a_desired->freq = 48000;
|
|
179 a_desired->format = AUDIO_S16SYS;
|
|
180 a_desired->channels = 2;
|
|
181
|
|
182 // Initialize mixing device
|
|
183 fprintf(stderr, "Initializing miniJSS mixer with: %d, %d, %d\n",
|
|
184 JSS_AUDIO_S16, a_desired->channels, a_desired->freq);
|
|
185
|
|
186 d = jvmInit(JSS_AUDIO_S16, a_desired->channels, a_desired->freq, JMIX_AUTO);
|
|
187 if (!d) {
|
|
188 fprintf(stderr, "jvmInit() returned NULL\n");
|
|
189 return 3;
|
|
190 }
|
|
191
|
|
192 a_desired->samples = buflen;
|
|
193 a_desired->callback = audioCallback;
|
|
194 a_desired->userdata = (void *) d;
|
|
195
|
|
196 // Open the audio device
|
|
197 fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n",
|
|
198 a_desired->format, a_desired->channels, a_desired->freq);
|
|
199
|
|
200 if (SDL_OpenAudio(a_desired, a_obtained) < 0)
|
|
201 {
|
|
202 fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
|
|
203 return 4;
|
|
204 }
|
|
205
|
|
206 fprintf(stderr, "Got: %d, %d, %d\n",
|
|
207 a_obtained->format, a_obtained->channels, a_obtained->freq);
|
|
208
|
|
209 if ((a_obtained->format != a_desired->format) ||
|
|
210 (a_obtained->channels != a_desired->channels) ||
|
|
211 (a_obtained->freq != a_desired->freq))
|
|
212 {
|
|
213 fprintf(stderr, "Could not get wanted audio parameters from SDL!\n");
|
|
214 return 8;
|
|
215 }
|
|
216
|
|
217 free(a_desired);
|
|
218
|
|
219 // Initialize player
|
|
220 p = jmpInit(d);
|
|
221 if (!p)
|
|
222 {
|
|
223 fprintf(stderr, "jmpInit() returned NULL\n");
|
|
224 return 4;
|
|
225 }
|
|
226
|
|
227 // Set callback
|
|
228 jvmSetCallback(d, jmpExec, p);
|
|
229
|
|
230 // Initialize playing
|
|
231 jmpSetModule(p, m);
|
|
232 jmpPlayOrder(p, 0);
|
|
233 jvmSetGlobalVol(d, 60);
|
|
234
|
|
235 // okay, main loop here ... "play" module and print out info
|
|
236 printf("----------------------------------------------------\n");
|
|
237 SDL_PauseAudio(0);
|
|
238 while (p->isPlaying)
|
|
239 {
|
|
240 int r = p->iRow;
|
|
241 while (r == p->iRow && p->isPlaying)
|
|
242 SDL_Delay(50);
|
|
243
|
|
244 printRow(stdout, p->pPattern, p->iRow);
|
|
245 printf("\n");
|
|
246 }
|
|
247
|
|
248 printf("----------------------------------------------------\n");
|
|
249
|
|
250 // Free module data
|
|
251 jmpClose(p);
|
|
252 jvmClose(d);
|
|
253 jssFreeModule(m);
|
|
254 m = NULL;
|
|
255
|
|
256 return 0;
|
|
257 }
|