1 /*
2 * Schism Tracker - a cross-platform Impulse Tracker clone
3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5 * copyright (c) 2009 Storlek & Mrs. Brisby
6 * copyright (c) 2010-2012 Storlek
7 * URL: http://schismtracker.org/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #define NEED_BYTESWAP
25 #define NEED_TIME
26 #include "headers.h"
27
28 #include "it.h"
29 #include "sndfile.h"
30 #include "song.h"
31 #include "slurp.h"
32 #include "page.h"
33 #include "version.h"
34
35 #include "fmt.h"
36 #include "dmoz.h"
37
38 #include "it_defs.h"
39
40 #include "snd_gm.h"
41 #include "midi.h"
42 #include "disko.h"
43
44 #include <stdio.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <assert.h>
48
49 // ------------------------------------------------------------------------
50
51 char song_filename[PATH_MAX + 1];
52 char song_basename[NAME_MAX + 1];
53
54 // ------------------------------------------------------------------------
55 // replace any '\0' chars with spaces, mostly to make the string handling
56 // much easier.
57 // TODO | Maybe this should be done with the filenames and the song title
58 // TODO | as well? (though I've never come across any cases of either of
59 // TODO | these having null characters in them...)
60
_fix_names(song_t * qq)61 static void _fix_names(song_t *qq)
62 {
63 int c, n;
64
65 for (n = 1; n < MAX_INSTRUMENTS; n++) {
66 for (c = 0; c < 25; c++)
67 if (qq->samples[n].name[c] == 0)
68 qq->samples[n].name[c] = 32;
69 qq->samples[n].name[25] = 0;
70
71 if (!qq->instruments[n])
72 continue;
73 for (c = 0; c < 25; c++)
74 if (qq->instruments[n]->name[c] == 0)
75 qq->instruments[n]->name[c] = 32;
76 qq->instruments[n]->name[25] = 0;
77 }
78 }
79
80 // ------------------------------------------------------------------------
81 // file stuff
82
song_set_filename(const char * file)83 static void song_set_filename(const char *file)
84 {
85 if (file && file[0]) {
86 strncpy(song_filename, file, PATH_MAX);
87 strncpy(song_basename, get_basename(file), NAME_MAX);
88 song_filename[PATH_MAX] = '\0';
89 song_basename[NAME_MAX] = '\0';
90 } else {
91 song_filename[0] = '\0';
92 song_basename[0] = '\0';
93 }
94 }
95
96 // clear patterns => clear filename and save flag
97 // clear orderlist => clear title, message, and channel settings
song_new(int flags)98 void song_new(int flags)
99 {
100 int i;
101
102 song_lock_audio();
103
104 song_stop_unlocked(0);
105
106 if ((flags & KEEP_PATTERNS) == 0) {
107 song_set_filename(NULL);
108 status.flags &= ~SONG_NEEDS_SAVE;
109
110 for (i = 0; i < MAX_PATTERNS; i++) {
111 if (current_song->patterns[i]) {
112 csf_free_pattern(current_song->patterns[i]);
113 current_song->patterns[i] = NULL;
114 }
115 current_song->pattern_size[i] = 64;
116 current_song->pattern_alloc_size[i] = 64;
117 }
118 }
119 if ((flags & KEEP_SAMPLES) == 0) {
120 for (i = 1; i < MAX_SAMPLES; i++) {
121 if (current_song->samples[i].data) {
122 csf_free_sample(current_song->samples[i].data);
123 }
124 }
125 memset(current_song->samples, 0, sizeof(current_song->samples));
126 for (i = 1; i < MAX_SAMPLES; i++) {
127 current_song->samples[i].c5speed = 8363;
128 current_song->samples[i].volume = 64 * 4;
129 current_song->samples[i].global_volume = 64;
130 }
131 }
132 if ((flags & KEEP_INSTRUMENTS) == 0) {
133 for (i = 0; i < MAX_INSTRUMENTS; i++) {
134 if (current_song->instruments[i]) {
135 csf_free_instrument(current_song->instruments[i]);
136 current_song->instruments[i] = NULL;
137 }
138 }
139 }
140 if ((flags & KEEP_ORDERLIST) == 0) {
141 memset(current_song->orderlist, ORDER_LAST, sizeof(current_song->orderlist));
142 memset(current_song->title, 0, sizeof(current_song->title));
143 memset(current_song->message, 0, MAX_MESSAGE);
144
145 for (i = 0; i < 64; i++) {
146 current_song->channels[i].volume = 64;
147 current_song->channels[i].panning = 128;
148 current_song->channels[i].flags = 0;
149 current_song->voices[i].volume = 256;
150 current_song->voices[i].global_volume = current_song->channels[i].volume;
151 current_song->voices[i].panning = current_song->channels[i].panning;
152 current_song->voices[i].flags = current_song->channels[i].flags;
153 current_song->voices[i].cutoff = 0x7F;
154 }
155 }
156
157 current_song->repeat_count = 0;
158 //song_stop();
159
160 csf_forget_history(current_song);
161
162 song_unlock_audio();
163
164 main_song_changed_cb();
165 }
166
167 // ------------------------------------------------------------------------------------------------------------
168
169 #define LOAD_SONG(x) fmt_##x##_load_song,
170 static fmt_load_song_func load_song_funcs[] = {
171 #include "fmt-types.h"
172 NULL,
173 };
174
175
fmt_strerror(int n)176 const char *fmt_strerror(int n)
177 {
178 switch (n) {
179 case -LOAD_UNSUPPORTED:
180 return "Unrecognised file type";
181 case -LOAD_FORMAT_ERROR:
182 return "File format error (corrupt?)";
183 default:
184 return strerror(errno);
185 }
186 }
187
188 // IT uses \r in song messages; replace errant \n's
message_convert_newlines(song_t * song)189 void message_convert_newlines(song_t *song) {
190 int i = 0, len = strlen(song->message);
191 for (i = 0; i < len; i++) {
192 if (song->message[i] == '\n') {
193 song->message[i] = '\r';
194 }
195 }
196 }
197
song_create_load(const char * file)198 song_t *song_create_load(const char *file)
199 {
200 fmt_load_song_func *func;
201 int ok = 0, err = 0;
202
203 slurp_t *s = slurp(file, NULL, 0);
204 if (!s)
205 return NULL;
206
207 song_t *newsong = csf_allocate();
208
209 if (current_song) {
210 newsong->mix_flags = current_song->mix_flags;
211 csf_set_wave_config(newsong,
212 current_song->mix_frequency,
213 current_song->mix_bits_per_sample,
214 current_song->mix_channels);
215
216 // loaders might override these
217 newsong->row_highlight_major = current_song->row_highlight_major;
218 newsong->row_highlight_minor = current_song->row_highlight_minor;
219 csf_copy_midi_cfg(newsong, current_song);
220 }
221
222 for (func = load_song_funcs; *func && !ok; func++) {
223 slurp_rewind(s);
224 switch ((*func)(newsong, s, 0)) {
225 case LOAD_SUCCESS:
226 err = 0;
227 ok = 1;
228 break;
229 case LOAD_UNSUPPORTED:
230 err = -LOAD_UNSUPPORTED;
231 continue;
232 case LOAD_FORMAT_ERROR:
233 err = -LOAD_FORMAT_ERROR;
234 break;
235 case LOAD_FILE_ERROR:
236 err = errno;
237 break;
238 }
239 if (err) {
240 csf_free(newsong);
241 unslurp(s);
242 errno = err;
243 return NULL;
244 }
245 }
246
247 unslurp(s);
248
249 if (err) {
250 // awwww, nerts!
251 csf_free(newsong);
252 errno = err;
253 return NULL;
254 }
255
256 newsong->stop_at_order = newsong->stop_at_row = -1;
257 message_convert_newlines(newsong);
258 message_reset_selection();
259
260 return newsong;
261 }
262
song_load_unchecked(const char * file)263 int song_load_unchecked(const char *file)
264 {
265 const char *base = get_basename(file);
266 int was_playing;
267 song_t *newsong;
268
269 // IT stops the song even if the new song can't be loaded
270 if (status.flags & PLAY_AFTER_LOAD) {
271 was_playing = (song_get_mode() == MODE_PLAYING);
272 } else {
273 was_playing = 0;
274 song_stop();
275 }
276
277 log_nl();
278 log_nl();
279 log_appendf(2, "Loading %s", base);
280 log_underline(strlen(base) + 8);
281
282 newsong = song_create_load(file);
283 if (!newsong) {
284 log_appendf(4, " %s", fmt_strerror(errno));
285 return 0;
286 }
287
288
289 song_set_filename(file);
290
291 song_lock_audio();
292 csf_free(current_song);
293 current_song = newsong;
294 current_song->repeat_count = 0;
295 max_channels_used = 0;
296 _fix_names(current_song);
297 song_stop_unlocked(0);
298 song_unlock_audio();
299
300 if (was_playing && (status.flags & PLAY_AFTER_LOAD))
301 song_start();
302
303 main_song_changed_cb();
304
305 status.flags &= ~SONG_NEEDS_SAVE;
306
307 // print out some stuff
308 const char *tid = current_song->tracker_id;
309
310 char fmt[] = " %d patterns, %d samples, %d instruments";
311 int n, nsmp, nins;
312 song_sample_t *smp;
313 song_instrument_t **ins;
314
315 for (n = 0, smp = current_song->samples + 1, nsmp = 0; n < MAX_SAMPLES; n++, smp++)
316 if (smp->data)
317 nsmp++;
318 for (n = 0, ins = current_song->instruments + 1, nins = 0; n < MAX_INSTRUMENTS; n++, ins++)
319 if (*ins != NULL)
320 nins++;
321
322 if (tid[0])
323 log_appendf(5, " %s", tid);
324 if (!nins)
325 *strrchr(fmt, ',') = 0; // cut off 'instruments'
326 log_appendf(5, fmt, csf_get_num_patterns(current_song), nsmp, nins);
327
328
329 return 1;
330 }
331
332 // ------------------------------------------------------------------------------------------------------------
333
334 static song_instrument_t blank_instrument; // should be zero, it's coming from bss
335
336 // set iti_file if saving an instrument to disk by itself
_save_it_instrument(int n,disko_t * fp,int iti_file)337 static void _save_it_instrument(int n, disko_t *fp, int iti_file)
338 {
339 n++; // FIXME: this is dumb; really all the numbering should be one-based to make it simple
340
341 struct it_instrument iti = {};
342 song_instrument_t *i = current_song->instruments[n];
343
344 if (!i)
345 i = &blank_instrument;
346
347 // envelope: flags num lpb lpe slb sle data[25*3] reserved
348
349 iti.id = bswapLE32(0x49504D49); // IMPI
350 strncpy((char *) iti.filename, (char *) i->filename, 12);
351 iti.zero = 0;
352 iti.nna = i->nna;
353 iti.dct = i->dct;
354 iti.dca = i->dca;
355 iti.fadeout = bswapLE16(i->fadeout >> 5);
356 iti.pps = i->pitch_pan_separation;
357 iti.ppc = i->pitch_pan_center;
358 iti.gbv = i->global_volume;
359 iti.dfp = i->panning / 4;
360 if (!(i->flags & ENV_SETPANNING))
361 iti.dfp |= 0x80;
362 iti.rv = i->vol_swing;
363 iti.rp = i->pan_swing;
364 if (iti_file) {
365 iti.trkvers = bswapLE16(0x1000 | ver_cwtv);
366 }
367 // reserved1
368 strncpy((char *) iti.name, (char *) i->name, 25);
369 iti.name[25] = 0;
370 iti.ifc = i->ifc;
371 iti.ifr = i->ifr;
372 iti.mch = 0;
373 if(i->midi_channel_mask >= 0x10000)
374 {
375 iti.mch = i->midi_channel_mask - 0x10000;
376 if(iti.mch <= 16) iti.mch = 16;
377 }
378 else if(i->midi_channel_mask & 0xFFFF)
379 {
380 iti.mch = 1;
381 while(!(i->midi_channel_mask & (1 << (iti.mch-1)))) ++iti.mch;
382 }
383 iti.mpr = i->midi_program;
384 iti.mbank = bswapLE16(i->midi_bank);
385
386 static int iti_map[255];
387 static int iti_invmap[255];
388 static int iti_nalloc = 0;
389
390 iti_nalloc = 0;
391 for (int j = 0; j < 255; j++) {
392 iti_map[j] = -1;
393 }
394 for (int j = 0; j < 120; j++) {
395 if (iti_file) {
396 int o = i->sample_map[j];
397 if (o > 0 && o < 255 && iti_map[o] == -1) {
398 iti_map[o] = iti_nalloc;
399 iti_invmap[iti_nalloc] = o;
400 iti_nalloc++;
401 }
402 iti.keyboard[2 * j + 1] = iti_map[o]+1;
403 } else {
404 iti.keyboard[2 * j + 1] = i->sample_map[j];
405 }
406 iti.keyboard[2 * j] = i->note_map[j] - 1;
407 }
408 if (iti_file) {
409 iti.nos = (uint8_t)iti_nalloc;
410 }
411 // envelope stuff from modplug
412 iti.volenv.flags = 0;
413 iti.panenv.flags = 0;
414 iti.pitchenv.flags = 0;
415 if (i->flags & ENV_VOLUME) iti.volenv.flags |= 0x01;
416 if (i->flags & ENV_VOLLOOP) iti.volenv.flags |= 0x02;
417 if (i->flags & ENV_VOLSUSTAIN) iti.volenv.flags |= 0x04;
418 if (i->flags & ENV_VOLCARRY) iti.volenv.flags |= 0x08;
419 iti.volenv.num = i->vol_env.nodes;
420 iti.volenv.lpb = i->vol_env.loop_start;
421 iti.volenv.lpe = i->vol_env.loop_end;
422 iti.volenv.slb = i->vol_env.sustain_start;
423 iti.volenv.sle = i->vol_env.sustain_end;
424 if (i->flags & ENV_PANNING) iti.panenv.flags |= 0x01;
425 if (i->flags & ENV_PANLOOP) iti.panenv.flags |= 0x02;
426 if (i->flags & ENV_PANSUSTAIN) iti.panenv.flags |= 0x04;
427 if (i->flags & ENV_PANCARRY) iti.panenv.flags |= 0x08;
428 iti.panenv.num = i->pan_env.nodes;
429 iti.panenv.lpb = i->pan_env.loop_start;
430 iti.panenv.lpe = i->pan_env.loop_end;
431 iti.panenv.slb = i->pan_env.sustain_start;
432 iti.panenv.sle = i->pan_env.sustain_end;
433 if (i->flags & ENV_PITCH) iti.pitchenv.flags |= 0x01;
434 if (i->flags & ENV_PITCHLOOP) iti.pitchenv.flags |= 0x02;
435 if (i->flags & ENV_PITCHSUSTAIN) iti.pitchenv.flags |= 0x04;
436 if (i->flags & ENV_PITCHCARRY) iti.pitchenv.flags |= 0x08;
437 if (i->flags & ENV_FILTER) iti.pitchenv.flags |= 0x80;
438 iti.pitchenv.num = i->pitch_env.nodes;
439 iti.pitchenv.lpb = i->pitch_env.loop_start;
440 iti.pitchenv.lpe = i->pitch_env.loop_end;
441 iti.pitchenv.slb = i->pitch_env.sustain_start;
442 iti.pitchenv.sle = i->pitch_env.sustain_end;
443 for (int j = 0; j < 25; j++) {
444 iti.volenv.data[3 * j] = i->vol_env.values[j];
445 iti.volenv.data[3 * j + 1] = i->vol_env.ticks[j] & 0xFF;
446 iti.volenv.data[3 * j + 2] = i->vol_env.ticks[j] >> 8;
447 iti.panenv.data[3 * j] = i->pan_env.values[j] - 32;
448 iti.panenv.data[3 * j + 1] = i->pan_env.ticks[j] & 0xFF;
449 iti.panenv.data[3 * j + 2] = i->pan_env.ticks[j] >> 8;
450 iti.pitchenv.data[3 * j] = i->pitch_env.values[j] - 32;
451 iti.pitchenv.data[3 * j + 1] = i->pitch_env.ticks[j] & 0xFF;
452 iti.pitchenv.data[3 * j + 2] = i->pitch_env.ticks[j] >> 8;
453 }
454
455 // ITI files *need* to write 554 bytes due to alignment, but in a song it doesn't matter
456 disko_write(fp, &iti, sizeof(iti));
457 if (iti_file) {
458 if (sizeof(iti) < 554) {
459 for (int j = sizeof(iti); j < 554; j++) {
460 disko_write(fp, "\x0", 1);
461 }
462 }
463 assert(sizeof(iti) <= 554);
464
465 unsigned int qp = 554;
466 /* okay, now go through samples */
467 for (int j = 0; j < iti_nalloc; j++) {
468 int o = iti_invmap[ j ];
469
470 iti_map[o] = qp;
471 qp += 80; /* header is 80 bytes */
472 save_its_header(fp, current_song->samples + o);
473 }
474 for (int j = 0; j < iti_nalloc; j++) {
475 unsigned int op, tmp;
476
477 int o = iti_invmap[ j ];
478
479 song_sample_t *smp = current_song->samples + o;
480
481 op = disko_tell(fp);
482 tmp = bswapLE32(op);
483 disko_seek(fp, iti_map[o]+0x48, SEEK_SET);
484 disko_write(fp, &tmp, 4);
485 disko_seek(fp, op, SEEK_SET);
486 csf_write_sample(fp, smp, SF_LE | SF_PCMS
487 | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
488 | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M),
489 UINT32_MAX);
490 }
491 }
492 }
493
494 // NOBODY expects the Spanish Inquisition!
_save_it_pattern(disko_t * fp,song_note_t * pat,int patsize)495 static void _save_it_pattern(disko_t *fp, song_note_t *pat, int patsize)
496 {
497 song_note_t *noteptr = pat;
498 song_note_t lastnote[64] = {};
499 uint8_t initmask[64] = {};
500 uint8_t lastmask[64];
501 unsigned short pos = 0;
502 uint8_t data[65536];
503
504 memset(lastmask, 0xff, 64);
505
506 for (int row = 0; row < patsize; row++) {
507 for (int chan = 0; chan < 64; chan++, noteptr++) {
508 uint8_t m = 0; // current mask
509 int vol = -1;
510 unsigned int note = noteptr->note;
511 uint8_t effect = noteptr->effect, param = noteptr->param;
512
513 if (note) {
514 m |= 1;
515 if (note < 0x80)
516 note--;
517 }
518 if (noteptr->instrument) m |= 2;
519 switch (noteptr->voleffect) {
520 default: break;
521 case VOLFX_VOLUME: vol = MIN(noteptr->volparam, 64); break;
522 case VOLFX_FINEVOLUP: vol = MIN(noteptr->volparam, 9) + 65; break;
523 case VOLFX_FINEVOLDOWN: vol = MIN(noteptr->volparam, 9) + 75; break;
524 case VOLFX_VOLSLIDEUP: vol = MIN(noteptr->volparam, 9) + 85; break;
525 case VOLFX_VOLSLIDEDOWN: vol = MIN(noteptr->volparam, 9) + 95; break;
526 case VOLFX_PORTADOWN: vol = MIN(noteptr->volparam, 9) + 105; break;
527 case VOLFX_PORTAUP: vol = MIN(noteptr->volparam, 9) + 115; break;
528 case VOLFX_PANNING: vol = MIN(noteptr->volparam, 64) + 128; break;
529 case VOLFX_VIBRATODEPTH: vol = MIN(noteptr->volparam, 9) + 203; break;
530 case VOLFX_VIBRATOSPEED: vol = 203; break;
531 case VOLFX_TONEPORTAMENTO: vol = MIN(noteptr->volparam, 9) + 193; break;
532 }
533 if (vol != -1) m |= 4;
534 csf_export_s3m_effect(&effect, ¶m, 1);
535 if (effect || param) m |= 8;
536 if (!m) continue;
537
538 if (m & 1) {
539 if ((note == lastnote[chan].note) && (initmask[chan] & 1)) {
540 m &= ~1;
541 m |= 0x10;
542 } else {
543 lastnote[chan].note = note;
544 initmask[chan] |= 1;
545 }
546 }
547 if (m & 2) {
548 if ((noteptr->instrument == lastnote[chan].instrument) && (initmask[chan] & 2)) {
549 m &= ~2;
550 m |= 0x20;
551 } else {
552 lastnote[chan].instrument = noteptr->instrument;
553 initmask[chan] |= 2;
554 }
555 }
556 if (m & 4) {
557 if ((vol == lastnote[chan].volparam) && (initmask[chan] & 4)) {
558 m &= ~4;
559 m |= 0x40;
560 } else {
561 lastnote[chan].volparam = vol;
562 initmask[chan] |= 4;
563 }
564 }
565 if (m & 8) {
566 if ((effect == lastnote[chan].effect) && (param == lastnote[chan].param)
567 && (initmask[chan] & 8)) {
568 m &= ~8;
569 m |= 0x80;
570 } else {
571 lastnote[chan].effect = effect;
572 lastnote[chan].param = param;
573 initmask[chan] |= 8;
574 }
575 }
576 if (m == lastmask[chan]) {
577 data[pos++] = chan + 1;
578 } else {
579 lastmask[chan] = m;
580 data[pos++] = (chan + 1) | 0x80;
581 data[pos++] = m;
582 }
583 if (m & 1) data[pos++] = note;
584 if (m & 2) data[pos++] = noteptr->instrument;
585 if (m & 4) data[pos++] = vol;
586 if (m & 8) {
587 data[pos++] = effect;
588 data[pos++] = param;
589 }
590 } // end channel
591 data[pos++] = 0;
592 } // end row
593
594 // write the data to the file (finally!)
595 unsigned short h[4] = {0};
596 h[0] = bswapLE16(pos);
597 h[1] = bswapLE16(patsize);
598 // h[2] and h[3] are meaningless
599 disko_write(fp, &h, 8);
600 disko_write(fp, data, pos);
601 }
602
603 // why on earth isn't this using the 'song' parameter? will finding this out hurt my head?
_save_it(disko_t * fp,UNUSED song_t * song)604 static int _save_it(disko_t *fp, UNUSED song_t *song)
605 {
606 struct it_file hdr = {};
607 int n;
608 int nord, nins, nsmp, npat;
609 int msglen = strlen(current_song->message);
610 int warned_adlib = 0;
611 uint32_t para_ins[256], para_smp[256], para_pat[256];
612 // how much extra data is stuffed between the parapointers and the rest of the file
613 // (2 bytes for edit history length, and 8 per entry including the current session)
614 uint32_t extra = 2 + 8 * current_song->histlen + 8;
615
616 // TODO complain about nonstandard stuff? or just stop saving it to begin with
617
618 /* IT always saves at least two orders -- and requires an extra order at the end (which gets chopped!)
619 However, the loader refuses to load files with too much data in the orderlist, so in the pathological
620 case where order 255 has data, writing an extra 0xFF at the end will result in a file that can't be
621 loaded back (for now). Eventually this can be fixed, but at least for a while it's probably a great
622 idea not to save things that other versions won't load. */
623 nord = csf_get_num_orders(current_song);
624 nord = CLAMP(nord + 1, 2, MAX_ORDERS);
625
626 nins = csf_get_num_instruments(current_song);
627 nsmp = csf_get_num_samples(current_song);
628
629 // IT always saves at least one pattern.
630 npat = csf_get_num_patterns(current_song) ?: 1;
631
632 hdr.id = bswapLE32(0x4D504D49); // IMPM
633 strncpy((char *) hdr.songname, current_song->title, 25);
634 hdr.songname[25] = 0;
635 hdr.hilight_major = current_song->row_highlight_major;
636 hdr.hilight_minor = current_song->row_highlight_minor;
637 hdr.ordnum = bswapLE16(nord);
638 hdr.insnum = bswapLE16(nins);
639 hdr.smpnum = bswapLE16(nsmp);
640 hdr.patnum = bswapLE16(npat);
641 // No one else seems to be using the cwtv's tracker id number, so I'm gonna take 1. :)
642 hdr.cwtv = bswapLE16(0x1000 | ver_cwtv); // cwtv 0xtxyy = tracker id t, version x.yy
643 // compat:
644 // really simple IT files = 1.00 (when?)
645 // "normal" = 2.00
646 // vol col effects = 2.08
647 // pitch wheel depth = 2.13
648 // embedded midi config = 2.13
649 // row highlight = 2.13 (doesn't necessarily affect cmwt)
650 // compressed samples = 2.14
651 // instrument filters = 2.17
652 hdr.cmwt = bswapLE16(0x0214); // compatible with IT 2.14
653 for (n = 1; n < nins; n++) {
654 song_instrument_t *i = current_song->instruments[n];
655 if (!i) continue;
656 if (i->flags & ENV_FILTER) {
657 hdr.cmwt = bswapLE16(0x0217);
658 break;
659 }
660 }
661
662 hdr.flags = 0;
663 hdr.special = 2 | 4; // 2 = edit history, 4 = row highlight
664
665 if (song_is_stereo()) hdr.flags |= 1;
666 if (song_is_instrument_mode()) hdr.flags |= 4;
667 if (song_has_linear_pitch_slides()) hdr.flags |= 8;
668 if (song_has_old_effects()) hdr.flags |= 16;
669 if (song_has_compatible_gxx()) hdr.flags |= 32;
670 if (midi_flags & MIDI_PITCHBEND) {
671 hdr.flags |= 64;
672 hdr.pwd = midi_pitch_depth;
673 }
674 if (current_song->flags & SONG_EMBEDMIDICFG) {
675 hdr.flags |= 128;
676 hdr.special |= 8;
677 extra += sizeof(midi_config_t);
678 }
679 hdr.flags = bswapLE16(hdr.flags);
680 if (msglen) {
681 hdr.special |= 1;
682 msglen++;
683 }
684 hdr.special = bswapLE16(hdr.special);
685
686 // 16+ = reserved (always off?)
687 hdr.globalvol = current_song->initial_global_volume;
688 hdr.mv = current_song->mixing_volume;
689 hdr.speed = current_song->initial_speed;
690 hdr.tempo = current_song->initial_tempo;
691 hdr.sep = current_song->pan_separation;
692 if (msglen) {
693 hdr.msgoffset = bswapLE32(extra + 0xc0 + nord + 4 * (nins + nsmp + npat));
694 hdr.msglength = bswapLE16(msglen);
695 }
696 hdr.reserved = bswapLE32(ver_reserved);
697
698 for (n = 0; n < 64; n++) {
699 hdr.chnpan[n] = ((current_song->channels[n].flags & CHN_SURROUND)
700 ? 100 : (current_song->channels[n].panning / 4));
701 hdr.chnvol[n] = current_song->channels[n].volume;
702 if (current_song->channels[n].flags & CHN_MUTE)
703 hdr.chnpan[n] += 128;
704 }
705
706 disko_write(fp, &hdr, sizeof(hdr));
707 disko_write(fp, current_song->orderlist, nord);
708
709 // we'll get back to these later
710 disko_write(fp, para_ins, 4*nins);
711 disko_write(fp, para_smp, 4*nsmp);
712 disko_write(fp, para_pat, 4*npat);
713
714 // edit history (see scripts/timestamp.py)
715 // Should™ be fully compatible with Impulse Tracker.
716 struct timeval savetime, elapsed;
717 struct tm loadtm;
718 uint16_t h;
719 //x86/x64 compatibility
720 time_t thetime = current_song->editstart.tv_sec;
721 localtime_r(&thetime, &loadtm);
722 gettimeofday(&savetime, NULL);
723 timersub(&savetime, ¤t_song->editstart, &elapsed);
724
725 // item count
726 h = current_song->histlen + 1;
727 h = bswapLE16(h);
728 disko_write(fp, &h, 2);
729 // old data
730 disko_write(fp, current_song->histdata, 8 * current_song->histlen);
731 // 16-bit date
732 h = loadtm.tm_mday | ((loadtm.tm_mon + 1) << 5) | ((loadtm.tm_year - 80) << 9);
733 h = bswapLE16(h);
734 disko_write(fp, &h, 2);
735 // 16-bit time
736 h = (loadtm.tm_sec / 2) | (loadtm.tm_min << 5) | (loadtm.tm_hour << 11);
737 h = bswapLE16(h);
738 disko_write(fp, &h, 2);
739 // 32-bit DOS tick count (tick = 1/18.2 second; 54945 * 18.2 = 999999 which is Close Enough)
740 uint32_t ticks = elapsed.tv_sec * 182 / 10 + elapsed.tv_usec / 54945;
741 ticks = bswapLE32(ticks);
742 disko_write(fp, &ticks, 4);
743
744 // here comes MIDI configuration
745 // here comes MIDI configuration
746 // right down MIDI configuration lane
747 if (current_song->flags & SONG_EMBEDMIDICFG) {
748 disko_write(fp, ¤t_song->midi_config, sizeof(current_song->midi_config));
749 }
750
751 disko_write(fp, current_song->message, msglen);
752
753 // instruments, samples, and patterns
754 for (n = 0; n < nins; n++) {
755 para_ins[n] = disko_tell(fp);
756 para_ins[n] = bswapLE32(para_ins[n]);
757 _save_it_instrument(n, fp, 0);
758 }
759 for (n = 0; n < nsmp; n++) {
760 // the sample parapointers are byte-swapped later
761 para_smp[n] = disko_tell(fp);
762 save_its_header(fp, current_song->samples + n + 1);
763 }
764 for (n = 0; n < npat; n++) {
765 if (csf_pattern_is_empty(current_song, n)) {
766 para_pat[n] = 0;
767 } else {
768 para_pat[n] = disko_tell(fp);
769 para_pat[n] = bswapLE32(para_pat[n]);
770 _save_it_pattern(fp, current_song->patterns[n], current_song->pattern_size[n]);
771 }
772 }
773
774 // sample data
775 for (n = 0; n < nsmp; n++) {
776 unsigned int tmp, op;
777 song_sample_t *smp = current_song->samples + (n + 1);
778
779 // Always save the data pointer, even if there's not actually any data being pointed to
780 op = disko_tell(fp);
781 tmp = bswapLE32(op);
782 disko_seek(fp, para_smp[n]+0x48, SEEK_SET);
783 disko_write(fp, &tmp, 4);
784 disko_seek(fp, op, SEEK_SET);
785 if (smp->data)
786 csf_write_sample(fp, smp, SF_LE | SF_PCMS
787 | ((smp->flags & CHN_16BIT) ? SF_16 : SF_8)
788 | ((smp->flags & CHN_STEREO) ? SF_SS : SF_M),
789 UINT32_MAX);
790 // done using the pointer internally, so *now* swap it
791 para_smp[n] = bswapLE32(para_smp[n]);
792
793 if (!warned_adlib && smp->flags & CHN_ADLIB) {
794 log_appendf(4, " Warning: AdLib samples unsupported in IT format");
795 warned_adlib = 1;
796 }
797 }
798
799 // rewrite the parapointers
800 disko_seek(fp, 0xc0 + nord, SEEK_SET);
801 disko_write(fp, para_ins, 4*nins);
802 disko_write(fp, para_smp, 4*nsmp);
803 disko_write(fp, para_pat, 4*npat);
804
805 return SAVE_SUCCESS;
806 }
807
808 /* ------------------------------------------------------------------------- */
809
810 const struct save_format song_save_formats[] = {
811 {"IT", "Impulse Tracker", ".it", {.save_song = _save_it}},
812 {"S3M", "Scream Tracker 3", ".s3m", {.save_song = fmt_s3m_save_song}},
813 {"MOD", "Amiga ProTracker", ".mod", {.save_song = fmt_mod_save_song}},
814 {.label = NULL}
815 };
816
817 #define EXPORT_FUNCS(t) \
818 fmt_##t##_export_head, fmt_##t##_export_silence, fmt_##t##_export_body, fmt_##t##_export_tail
819
820 const struct save_format song_export_formats[] = {
821 {"WAV", "WAV", ".wav", {.export = {EXPORT_FUNCS(wav), 0}}},
822 {"MWAV", "WAV multi-write", ".wav", {.export = {EXPORT_FUNCS(wav), 1}}},
823 {"AIFF", "Audio IFF", ".aiff", {.export = {EXPORT_FUNCS(aiff), 0}}},
824 {"MAIFF", "Audio IFF multi-write", ".aiff", {.export = {EXPORT_FUNCS(aiff), 1}}},
825 {.label = NULL}
826 };
827 // <distance> and maiff sounds like something you'd want to hug
828 // <distance> .. dont ask
829
830 const struct save_format sample_save_formats[] = {
831 {"ITS", "Impulse Tracker", ".its", {.save_sample = fmt_its_save_sample}},
832 //{"S3I", "Scream Tracker", ".s3i", {.save_sample = fmt_s3i_save_sample}},
833 {"AIFF", "Audio IFF", ".aiff", {.save_sample = fmt_aiff_save_sample}},
834 {"AU", "Sun/NeXT", ".au", {.save_sample = fmt_au_save_sample}},
835 {"WAV", "WAV", ".wav", {.save_sample = fmt_wav_save_sample}},
836 {"RAW", "Raw", ".raw", {.save_sample = fmt_raw_save_sample}},
837 {.label = NULL}
838 };
839
get_save_format(const struct save_format * formats,const char * label)840 static const struct save_format *get_save_format(const struct save_format *formats, const char *label)
841 {
842 int n;
843
844 if (!label) {
845 // why would this happen, ever?
846 log_appendf(4, "No file type given, very weird! (Try a different filename?)");
847 return NULL;
848 }
849
850 for (n = 0; formats[n].label; n++)
851 if (strcmp(formats[n].label, label) == 0)
852 return formats + n;
853
854 log_appendf(4, "Unknown save format %s", label);
855 return NULL;
856 }
857
858
mangle_filename(const char * in,const char * mid,const char * ext)859 static char *mangle_filename(const char *in, const char *mid, const char *ext)
860 {
861 char *ret;
862 const char *iext;
863 size_t baselen, rlen;
864
865 iext = get_extension(in);
866 rlen = baselen = iext - in;
867 if (mid)
868 rlen += strlen(mid);
869 if (iext[0])
870 rlen += strlen(iext);
871 else if (ext)
872 rlen += strlen(ext);
873 ret = malloc(rlen + 1); /* room for terminating \0 */
874 if (!ret)
875 return NULL;
876 strncpy(ret, in, baselen);
877 ret[baselen] = '\0';
878 if (mid)
879 strcat(ret, mid);
880 /* maybe output a warning if iext and ext differ? */
881 if (iext[0])
882 strcat(ret, iext);
883 else if (ext)
884 strcat(ret, ext);
885 return ret;
886 }
887
song_export(const char * filename,const char * type)888 int song_export(const char *filename, const char *type)
889 {
890 const struct save_format *format = get_save_format(song_export_formats, type);
891 const char *mid;
892 char *mangle;
893 int r;
894
895 if (!format)
896 return SAVE_INTERNAL_ERROR;
897
898 mid = (format->f.export.multi && strcasestr(filename, "%c") == NULL) ? ".%c" : NULL;
899 mangle = mangle_filename(filename, mid, format->ext);
900
901 log_nl();
902 log_nl();
903 log_appendf(2, "Exporting to %s", format->name);
904 log_underline(strlen(format->name) + 13);
905
906 /* disko does the rest of the log messages itself */
907 r = disko_export_song(mangle, format);
908 free(mangle);
909 switch (r) {
910 case DW_OK:
911 return SAVE_SUCCESS;
912 case DW_ERROR:
913 return SAVE_FILE_ERROR;
914 default:
915 return SAVE_INTERNAL_ERROR;
916 }
917 }
918
919
song_save(const char * filename,const char * type)920 int song_save(const char *filename, const char *type)
921 {
922 int ret, backup;
923 const struct save_format *format = get_save_format(song_save_formats, type);
924 char *mangle;
925
926 if (!format)
927 return SAVE_INTERNAL_ERROR;
928
929 mangle = mangle_filename(filename, NULL, format->ext);
930
931 log_nl();
932 log_nl();
933 log_appendf(2, "Saving %s module", format->name);
934 log_underline(strlen(format->name) + 14);
935
936 /* TODO: add or replace file extension as appropriate
937
938 From IT 2.10 update:
939 - Automatic filename extension replacement on Ctrl-S, so that if you press
940 Ctrl-S after loading a .MOD, .669, .MTM or .XM, the filename will be
941 automatically modified to have a .IT extension.
942
943 In IT, if the filename given has no extension ("basename"), then the extension for the proper file type
944 (IT/S3M) will be appended to the name.
945 A filename with an extension is not modified, even if the extension is blank. (as in "basename.")
946
947 This brings up a rather odd bit of behavior: what happens when saving a file with the deliberately wrong
948 extension? Selecting the IT type and saving as "test.s3m" works just as one would expect: an IT file is
949 written, with the name "test.s3m". No surprises yet, but as soon as Ctrl-S is used, the filename is "fixed",
950 producing a second file called "test.it". The reverse happens when trying to save an S3M named "test.it" --
951 it's rewritten to "test.s3m".
952 Note that in these scenarios, Impulse Tracker *DOES NOT* check if an existing file by that name exists; it
953 will GLADLY overwrite the old "test.s3m" (or .it) with the renamed file that's being saved. Presumably this
954 is NOT intentional behavior.
955
956 Another note: if the file could not be saved for some reason or another, Impulse Tracker pops up a dialog
957 saying "Could not save file". This can be seen rather easily by trying to save a file with a malformed name,
958 such as "abc|def.it". This dialog is presented both when saving from F10 and Ctrl-S.
959 */
960
961 disko_t *fp = disko_open(mangle);
962 if (!fp) {
963 log_perror(mangle);
964 free(mangle);
965 return SAVE_FILE_ERROR;
966 }
967
968 ret = format->f.save_song(fp, current_song);
969 if (ret != SAVE_SUCCESS)
970 disko_seterror(fp, EINVAL);
971 backup = ((status.flags & MAKE_BACKUPS)
972 ? (status.flags & NUMBERED_BACKUPS)
973 ? 65536 : 1 : 0);
974 if (disko_close(fp, backup) == DW_ERROR && ret == SAVE_SUCCESS) {
975 // this was not as successful as originally claimed!
976 ret = SAVE_FILE_ERROR;
977 }
978
979 switch (ret) {
980 case SAVE_SUCCESS:
981 status.flags &= ~SONG_NEEDS_SAVE;
982 if (strcasecmp(song_filename, mangle))
983 song_set_filename(mangle);
984 log_appendf(5, " Done");
985 break;
986 case SAVE_FILE_ERROR:
987 log_perror(mangle);
988 break;
989 case SAVE_INTERNAL_ERROR:
990 default: // ???
991 log_appendf(4, " Internal error saving song");
992 break;
993 }
994
995 free(mangle);
996 return ret;
997 }
998
song_save_sample(const char * filename,const char * type,song_sample_t * smp,int num)999 int song_save_sample(const char *filename, const char *type, song_sample_t *smp, int num)
1000 {
1001 int ret;
1002 const struct save_format *format = get_save_format(sample_save_formats, type);
1003
1004 if (!format)
1005 return SAVE_INTERNAL_ERROR;
1006
1007 if (!filename || !filename[0]) {
1008 status_text_flash("Error: Sample %d NOT saved! (%s)", num, "No Filename?");
1009 return SAVE_INTERNAL_ERROR; // ?
1010 }
1011
1012 disko_t *fp = disko_open(filename);
1013 if (fp) {
1014 ret = format->f.save_sample(fp, smp);
1015 if (ret != SAVE_SUCCESS)
1016 disko_seterror(fp, EINVAL);
1017 if (disko_close(fp, 0) == DW_ERROR && ret == SAVE_SUCCESS) {
1018 // this was not as successful as originally claimed!
1019 ret = SAVE_FILE_ERROR;
1020 }
1021 } else {
1022 ret = SAVE_FILE_ERROR;
1023 }
1024
1025 switch (ret) {
1026 case SAVE_SUCCESS:
1027 status_text_flash("%s sample saved (sample %d)", format->name, num);
1028 break;
1029 case SAVE_FILE_ERROR:
1030 status_text_flash("Error: Sample %d NOT saved! (%s)", num, "File Error");
1031 log_perror(get_basename(filename));
1032 break;
1033 case SAVE_INTERNAL_ERROR:
1034 default: // ???
1035 status_text_flash("Error: Sample %d NOT saved! (%s)", num, "Internal error");
1036 log_appendf(4, "Internal error saving sample");
1037 break;
1038 }
1039
1040 return ret;
1041 }
1042
1043 // ------------------------------------------------------------------------
1044
1045 // All of the sample's fields are initially zeroed except the filename (which is set to the sample's
1046 // basename and shouldn't be changed). A sample loader should not change anything in the sample until
1047 // it is sure that it can accept the file.
1048 // The title points to a buffer of 26 characters.
1049
1050 #define LOAD_SAMPLE(x) fmt_##x##_load_sample,
1051 static fmt_load_sample_func load_sample_funcs[] = {
1052 #include "fmt-types.h"
1053 NULL,
1054 };
1055
1056 #define LOAD_INSTRUMENT(x) fmt_##x##_load_instrument,
1057 static fmt_load_instrument_func load_instrument_funcs[] = {
1058 #include "fmt-types.h"
1059 NULL,
1060 };
1061
1062
song_clear_sample(int n)1063 void song_clear_sample(int n)
1064 {
1065 song_lock_audio();
1066 csf_destroy_sample(current_song, n);
1067 memset(current_song->samples + n, 0, sizeof(song_sample_t));
1068 current_song->samples[n].c5speed = 8363;
1069 current_song->samples[n].volume = 64 * 4;
1070 current_song->samples[n].global_volume = 64;
1071 song_unlock_audio();
1072 }
1073
song_copy_sample(int n,song_sample_t * src)1074 void song_copy_sample(int n, song_sample_t *src)
1075 {
1076 memcpy(current_song->samples + n, src, sizeof(song_sample_t));
1077
1078 if (src->data) {
1079 unsigned long bytelength = src->length;
1080 if (src->flags & CHN_16BIT)
1081 bytelength *= 2;
1082 if (src->flags & CHN_STEREO)
1083 bytelength *= 2;
1084
1085 current_song->samples[n].data = csf_allocate_sample(bytelength);
1086 memcpy(current_song->samples[n].data, src->data, bytelength);
1087 }
1088 }
1089
song_load_instrument_ex(int target,const char * file,const char * libf,int n)1090 int song_load_instrument_ex(int target, const char *file, const char *libf, int n)
1091 {
1092 slurp_t *s;
1093 int r, x;
1094
1095 song_lock_audio();
1096
1097 /* 0. delete old samples */
1098 if (current_song->instruments[target]) {
1099 int sampmap[MAX_SAMPLES] = {};
1100
1101 /* init... */
1102 for (unsigned int j = 0; j < 128; j++) {
1103 x = current_song->instruments[target]->sample_map[j];
1104 sampmap[x] = 1;
1105 }
1106 /* mark... */
1107 for (unsigned int q = 0; q < MAX_INSTRUMENTS; q++) {
1108 if ((int) q == target) continue;
1109 if (!current_song->instruments[q]) continue;
1110 for (unsigned int j = 0; j < 128; j++) {
1111 x = current_song->instruments[q]->sample_map[j];
1112 sampmap[x] = 0;
1113 }
1114 }
1115 /* sweep! */
1116 for (int j = 1; j < MAX_SAMPLES; j++) {
1117 if (!sampmap[j]) continue;
1118
1119 csf_destroy_sample(current_song, j);
1120 memset(current_song->samples + j, 0, sizeof(current_song->samples[j]));
1121 }
1122 /* now clear everything "empty" so we have extra slots */
1123 for (int j = 1; j < MAX_SAMPLES; j++) {
1124 if (csf_sample_is_empty(current_song->samples + j)) sampmap[j] = 0;
1125 }
1126 }
1127
1128 if (libf) { /* file is ignored */
1129 int sampmap[MAX_SAMPLES] = {};
1130
1131 song_t *xl = song_create_load(libf);
1132 if (!xl) {
1133 log_appendf(4, "%s: %s", libf, fmt_strerror(errno));
1134 song_unlock_audio();
1135 return 0;
1136 }
1137
1138 /* 1. find a place for all the samples */
1139 for (unsigned int j = 0; j < 128; j++) {
1140 x = xl->instruments[n]->sample_map[j];
1141 if (!sampmap[x]) {
1142 if (x > 0 && x < MAX_INSTRUMENTS) {
1143 for (int k = 1; k < MAX_SAMPLES; k++) {
1144 if (current_song->samples[k].length) continue;
1145 sampmap[x] = k;
1146 //song_sample *smp = (song_sample *)song_get_sample(k);
1147
1148 for (int c = 0; c < 25; c++) {
1149 if (xl->samples[x].name[c] == 0)
1150 xl->samples[x].name[c] = 32;
1151 }
1152 xl->samples[x].name[25] = 0;
1153
1154 song_copy_sample(k, &xl->samples[x]);
1155 break;
1156 }
1157 }
1158 }
1159 }
1160
1161 /* transfer the instrument */
1162 current_song->instruments[target] = xl->instruments[n];
1163 xl->instruments[n] = NULL; /* dangle */
1164
1165 /* and rewrite! */
1166 for (unsigned int k = 0; k < 128; k++) {
1167 current_song->instruments[target]->sample_map[k] = sampmap[
1168 current_song->instruments[target]->sample_map[k]
1169 ];
1170 }
1171
1172 song_unlock_audio();
1173 return 1;
1174 }
1175
1176 /* okay, load an ITI file */
1177 s = slurp(file, NULL, 0);
1178 if (!s) {
1179 log_perror(file);
1180 song_unlock_audio();
1181 return 0;
1182 }
1183
1184 r = 0;
1185 for (x = 0; load_instrument_funcs[x]; x++) {
1186 r = load_instrument_funcs[x](s->data, s->length, target);
1187 if (r) break;
1188 }
1189
1190 unslurp(s);
1191 song_unlock_audio();
1192
1193 return r;
1194 }
1195
song_load_instrument(int n,const char * file)1196 int song_load_instrument(int n, const char *file)
1197 {
1198 return song_load_instrument_ex(n,file,NULL,-1);
1199 }
1200
song_preload_sample(dmoz_file_t * file)1201 int song_preload_sample(dmoz_file_t *file)
1202 {
1203 // 0 is our "hidden sample"
1204 #define FAKE_SLOT 0
1205 //csf_stop_sample(current_song, current_song->samples + FAKE_SLOT);
1206 if (file->sample) {
1207 song_sample_t *smp = song_get_sample(FAKE_SLOT);
1208
1209 song_lock_audio();
1210 csf_destroy_sample(current_song, FAKE_SLOT);
1211 song_copy_sample(FAKE_SLOT, file->sample);
1212 strncpy(smp->name, file->title, 25);
1213 smp->name[25] = 0;
1214 strncpy(smp->filename, file->base, 12);
1215 smp->filename[12] = 0;
1216 song_unlock_audio();
1217 return FAKE_SLOT;
1218 }
1219 // WARNING this function must return 0 or KEYJAZZ_NOINST
1220 return song_load_sample(FAKE_SLOT, file->path) ? FAKE_SLOT : KEYJAZZ_NOINST;
1221 #undef FAKE_SLOT
1222 }
1223
song_load_sample(int n,const char * file)1224 int song_load_sample(int n, const char *file)
1225 {
1226 fmt_load_sample_func *load;
1227 song_sample_t smp = {};
1228
1229 const char *base = get_basename(file);
1230 slurp_t *s = slurp(file, NULL, 0);
1231
1232 if (s == NULL) {
1233 log_perror(base);
1234 return 0;
1235 }
1236
1237 // set some default stuff
1238 song_lock_audio();
1239 csf_stop_sample(current_song, current_song->samples + n);
1240 strncpy(smp.name, base, 25);
1241
1242 for (load = load_sample_funcs; *load; load++) {
1243 if ((*load)(s->data, s->length, &smp)) {
1244 break;
1245 }
1246 }
1247
1248 if (!load) {
1249 unslurp(s);
1250 log_perror(base);
1251 song_unlock_audio();
1252 return 0;
1253 }
1254
1255 // this is after the loaders because i don't trust them, even though i wrote them ;)
1256 strncpy(smp.filename, base, 12);
1257 smp.filename[12] = 0;
1258 smp.name[25] = 0;
1259
1260 csf_destroy_sample(current_song, n);
1261 if (((unsigned char)smp.name[23]) == 0xFF) {
1262 // don't load embedded samples
1263 // (huhwhat?!)
1264 smp.name[23] = ' ';
1265 }
1266 memcpy(&(current_song->samples[n]), &smp, sizeof(song_sample_t));
1267 song_unlock_audio();
1268
1269 unslurp(s);
1270
1271 return 1;
1272 }
1273
song_create_host_instrument(int smp)1274 void song_create_host_instrument(int smp)
1275 {
1276 int ins = instrument_get_current();
1277
1278 if (csf_instrument_is_empty(current_song->instruments[smp]))
1279 ins = smp;
1280 else if ((status.flags & CLASSIC_MODE) || !csf_instrument_is_empty(current_song->instruments[ins]))
1281 ins = csf_first_blank_instrument(current_song, 0);
1282
1283 if (ins > 0) {
1284 song_init_instrument_from_sample(ins, smp);
1285 status_text_flash("Sample assigned to Instrument %d", ins);
1286 } else {
1287 status_text_flash("Error: No available Instruments!");
1288 }
1289 }
1290
1291 // ------------------------------------------------------------------------
1292
song_save_instrument(int n,const char * file)1293 int song_save_instrument(int n, const char *file)
1294 {
1295 song_instrument_t *ins = current_song->instruments[n];
1296
1297 log_appendf(2, "Saving instrument %s", file);
1298 if (!ins) {
1299 /* this should never happen */
1300 log_appendf(4, "Instrument %d: there is no spoon", n);
1301 return 0;
1302 }
1303
1304 if (file[0] == '\0') {
1305 log_appendf(4, "Instrument %d: no filename", n);
1306 return 0;
1307 }
1308 disko_t *fp = disko_open(file);
1309 if (!fp) {
1310 log_perror(get_basename(file));
1311 return 0;
1312 }
1313 _save_it_instrument(n-1 /* grr.... */, fp, 1);
1314 if (disko_close(fp, 0) == DW_ERROR) {
1315 log_perror(get_basename(file));
1316 return 0;
1317 }
1318 return 1;
1319 }
1320
1321 // ------------------------------------------------------------------------
1322 // song information
1323
song_get_filename(void)1324 const char *song_get_filename(void)
1325 {
1326 return song_filename;
1327 }
1328
song_get_basename(void)1329 const char *song_get_basename(void)
1330 {
1331 return song_basename;
1332 }
1333
1334 // ------------------------------------------------------------------------
1335 // sample library browsing
1336
1337 // FIXME: unload the module when leaving the library 'directory'
1338 static song_t *library = NULL;
1339
1340
1341 // TODO: stat the file?
dmoz_read_instrument_library(const char * path,dmoz_filelist_t * flist,UNUSED dmoz_dirlist_t * dlist)1342 int dmoz_read_instrument_library(const char *path, dmoz_filelist_t *flist, UNUSED dmoz_dirlist_t *dlist)
1343 {
1344 unsigned int j;
1345 int x;
1346
1347 csf_stop_sample(current_song, current_song->samples + 0);
1348 csf_free(library);
1349
1350 const char *base = get_basename(path);
1351 library = song_create_load(path);
1352 if (!library) {
1353 log_appendf(4, "%s: %s", base, fmt_strerror(errno));
1354 return -1;
1355 }
1356
1357 for (int n = 1; n < MAX_INSTRUMENTS; n++) {
1358 if (!library->instruments[n])
1359 continue;
1360
1361 dmoz_file_t *file = dmoz_add_file(flist,
1362 str_dup(path), str_dup(base), NULL, n);
1363 file->title = str_dup(library->instruments[n]->name);
1364
1365 int count[128] = {};
1366
1367 file->sampsize = 0;
1368 file->filesize = 0;
1369 file->instnum = n;
1370 for (j = 0; j < 128; j++) {
1371 x = library->instruments[n]->sample_map[j];
1372 if (!count[x]) {
1373 if (x > 0 && x < MAX_INSTRUMENTS) {
1374 file->filesize += library->samples[x].length;
1375 file->sampsize++;
1376 }
1377 }
1378 count[x]++;
1379 }
1380
1381 file->type = TYPE_INST_ITI;
1382 file->description = "Fishcakes";
1383 // IT doesn't support this, despite it being useful.
1384 // Simply "unrecognized"
1385 }
1386
1387 return 0;
1388 }
1389
1390
dmoz_read_sample_library(const char * path,dmoz_filelist_t * flist,UNUSED dmoz_dirlist_t * dlist)1391 int dmoz_read_sample_library(const char *path, dmoz_filelist_t *flist, UNUSED dmoz_dirlist_t *dlist)
1392 {
1393 csf_stop_sample(current_song, current_song->samples + 0);
1394 csf_free(library);
1395
1396 const char *base = get_basename(path);
1397 library = song_create_load(path);
1398 if (!library) {
1399 /* FIXME: try loading as an instrument before giving up */
1400 log_appendf(4, "%s: %s", base, fmt_strerror(errno));
1401 errno = ENOTDIR;
1402 return -1;
1403 }
1404
1405 for (int n = 1; n < MAX_SAMPLES; n++) {
1406 if (library->samples[n].length) {
1407 for (int c = 0; c < 25; c++) {
1408 if (library->samples[n].name[c] == 0)
1409 library->samples[n].name[c] = 32;
1410 library->samples[n].name[25] = 0;
1411 }
1412 dmoz_file_t *file = dmoz_add_file(flist, str_dup(path), str_dup(base), NULL, n);
1413 file->type = TYPE_SAMPLE_EXTD;
1414 file->description = "Fishcakes"; // FIXME - what does IT say?
1415 file->smp_speed = library->samples[n].c5speed;
1416 file->smp_loop_start = library->samples[n].loop_start;
1417 file->smp_loop_end = library->samples[n].loop_end;
1418 file->smp_sustain_start = library->samples[n].sustain_start;
1419 file->smp_sustain_end = library->samples[n].sustain_end;
1420 file->smp_length = library->samples[n].length;
1421 file->smp_flags = library->samples[n].flags;
1422 file->smp_defvol = library->samples[n].volume>>2;
1423 file->smp_gblvol = library->samples[n].global_volume;
1424 file->smp_vibrato_speed = library->samples[n].vib_speed;
1425 file->smp_vibrato_depth = library->samples[n].vib_depth;
1426 file->smp_vibrato_rate = library->samples[n].vib_rate;
1427 // don't screw this up...
1428 if (((unsigned char)library->samples[n].name[23]) == 0xFF) {
1429 library->samples[n].name[23] = ' ';
1430 }
1431 file->title = str_dup(library->samples[n].name);
1432 file->sample = (song_sample_t *) library->samples + n;
1433 }
1434 }
1435
1436 return 0;
1437 }
1438
1439 // ------------------------------------------------------------------------
1440 // instrument loader
1441
instrument_loader_init(struct instrumentloader * ii,int slot)1442 song_instrument_t *instrument_loader_init(struct instrumentloader *ii, int slot)
1443 {
1444 ii->expect_samples = 0;
1445 ii->inst = song_get_instrument(slot);
1446 ii->slot = slot;
1447 ii->basex = 1;
1448 memset(ii->sample_map, 0, sizeof(ii->sample_map));
1449 return ii->inst;
1450 }
1451
instrument_loader_abort(struct instrumentloader * ii)1452 int instrument_loader_abort(struct instrumentloader *ii)
1453 {
1454 int n;
1455 song_wipe_instrument(ii->slot);
1456 for (n = 0; n < MAX_SAMPLES; n++) {
1457 if (ii->sample_map[n]) {
1458 song_clear_sample(ii->sample_map[n]-1);
1459 ii->sample_map[n] = 0;
1460 }
1461 }
1462 return 0;
1463 }
1464
instrument_loader_sample(struct instrumentloader * ii,int slot)1465 int instrument_loader_sample(struct instrumentloader *ii, int slot)
1466 {
1467 int x;
1468
1469 if (!slot) return 0;
1470 if (ii->sample_map[slot]) return ii->sample_map[slot];
1471 for (x = ii->basex; x < MAX_SAMPLES; x++) {
1472 song_sample_t *cur = (current_song->samples + x);
1473
1474 // if (!csf_sample_is_empty(current_song->samples + x))
1475 // continue;
1476 if (cur->data != NULL)
1477 continue;
1478
1479 ii->expect_samples++;
1480 ii->sample_map[slot] = x;
1481 ii->basex = x + 1;
1482 return ii->sample_map[slot];
1483 }
1484 status_text_flash("Too many samples");
1485 return 0;
1486 }
1487
1488