3 static uint16 periods[] = { 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 907};
4 static const String notes[12] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-"};
27 byte channelSettings[32];
28 } __attribute__((packed));
30 struct InstrumentHeader
49 } __attribute__((packed));
53 InstrumentHeader header;
64 } __attribute__((packed));
68 Note channels[32][64];
74 Array<byte> orders { };
75 Array<uint16> insPTR { };
76 Array<uint16> patPTR { };
78 Array<Instrument> instruments { };
79 Array<Pattern> patterns { };
82 bool Load(const char *fileName)
85 byte what, row, channel;
88 //Let's begin by opening the file...
89 File f = FileOpen(fileName, read);
92 printf("*** Loading S3M ******************\n");
93 printf("Loading header...\n");
95 f.Read(&header, sizeof(header), 1);
97 printf("Loading Order List...\n");
98 //Load Order List and pointers to instruments and patterns
99 orders.size = header.ordNum;
100 insPTR.size = header.insNum;
101 patPTR.size = header.patNum;
103 f.Read(orders.array, sizeof(byte), header.ordNum);
104 f.Read(insPTR.array, sizeof(uint16), header.insNum);
105 f.Read(patPTR.array, sizeof(uint16), header.patNum);
107 //Load channels panning positions
108 f.Read(panPos, sizeof(panPos), 1);
110 printf("Loading instruments...\n");
112 instruments.size = header.insNum;
113 for(i = 0; i<header.insNum; i++)
116 Instrument * ins = &instruments[i];
117 //Read Instrument header
118 f.Seek(insPTR[i] << 4, start);
119 f.Read(&ins->header, sizeof(InstrumentHeader), 1);
122 //Allocate and Read Instrument Sound
123 sound.data = new byte[ins->header.length];
124 f.Seek(ins->header.memSeg << 4, start);
125 f.Read(sound.data, ins->header.length, 1);
126 sound.channels = (ins->header.flags & 2) ? 2 : 1;
127 sound.bits = (ins->header.flags & 4) ? 16 : 8;
128 sound.length = ins->header.length;
129 sound.frequency = 22150*2;
131 printf("%i: %s\n", i, ins->header.name);
134 printf("Loading patterns...\n");
136 patterns.size = header.patNum;
138 printf("Not enough memory to load patterns!!\n");
139 for(p=0; p<header.patNum; p++)
141 Pattern * pat = &patterns[p];
142 for(row=0; row<64; row++)
145 pat->channels[c][row].note=0;
146 pat->channels[c][row].ins=0;
147 pat->channels[c][row].vol=255;
148 pat->channels[c][row].com=255;
149 pat->channels[c][row].info=0;
152 f.Seek(patPTR[p] << 4, start);
154 f.Read(&length, sizeof(uint16), 1);
157 f.Read(&what, sizeof(byte), 1);
169 f.Read(&pat->channels[channel][row].note, sizeof(byte), 1);
170 f.Read(&pat->channels[channel][row].ins, sizeof(byte), 1);
174 f.Read(&pat->channels[channel][row].vol, sizeof(byte), 1);
178 f.Read(&pat->channels[channel][row].com, sizeof(byte), 1);
179 f.Read(&pat->channels[channel][row].info, sizeof(byte), 1);
182 printf("Loading Pattern %i\n", p);
188 void PrintOut(Surface surface, uint16 pattern)
190 uint16 row, channel, note, octave, ins;
191 Pattern * pat = &patterns[pattern];
192 surface.WriteTextf(5,5, "Pattern %d", pattern);
193 for(row=0; row<64; row++)
195 for(channel=0; channel<32; channel++)
197 int x = (channel*8+2) * 8;
198 int y = (row+2) * 16;
199 note =pat->channels[channel][row].note&0x0F;
200 octave=(pat->channels[channel][row].note&0xF0)>>4;
201 ins =pat->channels[channel][row].ins;
203 surface.WriteTextf(x, y, "%s%i %i", notes[note], octave, octave);
205 surface.WriteTextf(x, y, "... ..");
218 void Stop(Mixer mixer, int channel)
220 Voice voice = voices[channel];
224 voice.looped = false;
225 voice.pos = voice.loopEnd;
230 void PlayNote(Mixer mixer, Instrument ins, uint16 note, uint16 octave, byte volume, uint16 channel)
232 uint32 note_st3period;
233 double vol = volume/255.0;
235 //while(note > 12) { note -= 12; octave++; }
239 note_st3period=(8363*16*((uint32)(periods[note])>>octave))/(uint32)ins.header.c2spd;
242 /*SND_SetLoop(ins->header.Flags&1, ins->header.LoopBegin, ins->header.LoopEnd, channel);
243 SND_SetFreq((uint32)(14317056L / note_st3period), channel);
245 SND_SetVolume(volume, channel);
246 SND_Play(ins.sound, channel);
248 //int c2spd = ins.header.c2spd;
249 //double freq = pow(Do_, note) * pow(2, octave-4) / (c2spd/8363.0);
250 double freq = 14317456.0 / note_st3period / 22150/2;
251 //double freq = 500.0/note_st3period;
252 Voice v = voices[channel-1];
256 v = mixer.Play(ins.sound, vol, bal, freq);
257 voices[channel-1] = v;
261 mixer.PlayInVoice(v, ins.sound, vol, bal, freq);
262 v.pos = offsets[channel-1];
263 v.loopStart = ins.header.loopBegin;
264 v.loopEnd = ins.header.loopEnd;
265 v.looped = ins.header.flags & 1;
270 Voice v = voices[channel-1];
280 uint16 order, pattern, row, channel;
282 Instrument *lastInst[32];
290 bool Play(Mixer mixer)
293 // int initSpeed = header.initSpeed;
294 Time time = /*pattern == 10*/ 1? speed/(1.1*45.5) : 0;
295 Time current = GetTime();
300 for(i = 0; i < 32; i ++)
303 pattern = orders[order];
304 tempo = header.initTempo;
305 speed = header.initSpeed;
307 SND_SetPB(&Instruments[0].Sound);
309 for(channel=0; channel<32; channel++)
310 SND_SetVolume(64, channel+1);
314 if((current-lastTick) >= time)
316 Pattern * pat = &patterns[pattern];
317 for(channel=0; channel<32; channel++)
319 Note * n = &pat->channels[channel][row];
320 bool gotVolume = false;
323 uint16 note = n->note&0x0F;
324 uint16 octave = (n->note&0xF0)>>4;
326 int volume = volumes[channel];
329 if(octave == 0xF && note == 0xE)
331 Stop(mixer, channel);
337 volumes[channel] = volume = vol;
341 Stop(mixer, channel);
343 if(com != 255 && com)
345 char fx = 'A'+(char)com-1;
346 printf("%c%02X\n", fx, info);
356 if((info & 0x0F) == 0x0)
357 slides[channel] = (info >> 4);
358 else if((info & 0x0F) == 0xF)
360 volume += (info >> 4);
361 if(volume > 63) volume = 63;
362 volumes[channel] = volume;
365 else if((info & 0xF0) == 0x0)
366 slides[channel] = -(info & 0x0F);
367 else if((info & 0xF0) == 0xF)
369 volume -= (info & 0x0F);
370 if(volume < 0) volume = 0;
371 volumes[channel] = volume;
378 offsets[channel] = info*256;
385 volume += slides[channel] * (speed-1);
386 volumes[channel] = volume;
387 if(volume > 63) volume = 63;
388 if(volume < 0) volume = 0;
394 lastInst[channel] = &instruments[ins-1];
395 PlayNote(mixer, ins ? &instruments[ins-1] : null, note, octave, lastInst[channel] ? (byte)(volume*lastInst[channel]->header.volume/63) : (byte)volume, channel+1);
397 offsets[channel] = 0;
402 for(channel=0; channel<32; channel++)
404 volumes[channel] = 63;
406 speed = header.initSpeed;
410 while(orders[order]==255)
413 if(order >= header.ordNum)
416 if(order >= header.ordNum)
420 for(channel=0; channel<32; channel++)
421 volumes[channel] = 63;
423 pattern = orders[order];
432 // There are 12 half-tones in an octave, and the frequency doubles in an octave.
434 define Do_ = 1.0594630943592952645618252949463; // The root 12 of 2.
440 define Sol = Fa_*Do_;
441 define Sol_ = Sol*Do_;
442 define La = Sol_*Do_;
447 class MainWindow : Window
451 borderStyle = sizable;
455 size = { 1024, 1120 };
463 mixer.systemHandle = systemHandle;
464 //s3m.Load("2ND_KEV.S3M");
465 //s3m.Load("2nd_pm.s3m");
466 //s3m.Load("theweird.s3m");
467 //s3m.Load("forgivme.s3m");
468 //s3m.Load("quiadroi.s3m");
469 //s3m.Load("everyido.s3m");
470 //s3m.Load("saywords.s3m");
471 s3m.Load("keven1.s3m");
472 //s3m.Load("trans.s3m");
474 instrument = s3m.instruments[0].sound;
497 bool OnKeyDown(Key key, unichar ch)
501 case f1: instrument = s3m.instruments[0].sound; break;
502 case f2: instrument = s3m.instruments[1].sound; break;
504 // The regular octave on the zxcvbn row, sharps above (asdf)
505 case z: mixer.Play(instrument, 1.0, -1, Do); break;
506 case x: mixer.Play(instrument, 1.0, -.8, Re); break;
507 case c: mixer.Play(instrument, 1.0, -.6, Mi); break;
508 case v: mixer.Play(instrument, 1.0, -.4, Fa); break;
509 case b: mixer.Play(instrument, 1.0, -.2, Sol); break;
510 case n: mixer.Play(instrument, 1.0, 0, La); break;
511 case m: mixer.Play(instrument, 1.0, .2, Si); break;
512 case comma: mixer.Play(instrument, 1.0, .4, Do*2); break;
513 case period:mixer.Play(instrument, 1.0, .6, Re*2); break;
514 case slash: mixer.Play(instrument, 1.0, .8, Mi*2); break;
515 case s: mixer.Play(instrument, 1.0, -.9, Do_); break;
516 case d: mixer.Play(instrument, 1.0, -.7, Re_); break;
517 case g: mixer.Play(instrument, 1.0, -.3, Fa_); break;
518 case h: mixer.Play(instrument, 1.0, -.1, Sol_); break;
519 case j: mixer.Play(instrument, 1.0, .1, La_); break;
520 case l: mixer.Play(instrument, 1.0, .5, Do_*2); break;
521 case colon: mixer.Play(instrument, 1.0, .7, Re_*2); break;
523 // The lower octave on the qwerty row, sharps above (digits)
524 case q: mixer.Play(instrument, 1.0, 0, Do/2); break;
525 case w: mixer.Play(instrument, 1.0, 0, Re/2); break;
526 case e: mixer.Play(instrument, 1.0, 0, Mi/2); break;
527 case r: mixer.Play(instrument, 1.0, 0, Fa/2); break;
528 case t: mixer.Play(instrument, 1.0, 0, Sol/2); break;
529 case y: mixer.Play(instrument, 1.0, 0, La/2); break;
530 case u: mixer.Play(instrument, 1.0, 0, Si/2); break;
531 case i: mixer.Play(instrument, 1.0, 0, Do); break;
532 case o: mixer.Play(instrument, 1.0, 0, Re); break;
533 case p: mixer.Play(instrument, 1.0, 0, Mi); break;
534 case k2: mixer.Play(instrument, 1.0, 0, Do_/2); break;
535 case k3: mixer.Play(instrument, 1.0, 0, Re_/2); break;
536 case k5: mixer.Play(instrument, 1.0, 0, Fa_/2); break;
537 case k6: mixer.Play(instrument, 1.0, 0, Sol_/2); break;
538 case k7: mixer.Play(instrument, 1.0, 0, La_/2); break;
539 case k9: mixer.Play(instrument, 1.0, 0, Do_); break;
540 case k0: mixer.Play(instrument, 1.0, 0, Re_); break;
545 void OnRedraw(Surface surface)
547 surface.foreground = mintCream;
548 s3m.PrintOut(surface, s3m.pattern);
549 surface.background = lime;
550 surface.Area(0, (s3m.row+2) * 16, 10, (s3m.row+2) * 16 + 15);
554 MainWindow mainWindow { };
556 class App : GuiApplication
558 timerResolution = 60;