Пример #1
0
static int load_s3i_sample(const uint8_t *data, size_t length, song_sample_t *smp)
{
        const struct s3i_header* header = (const struct s3i_header*) data;
        /*
        fprintf(stderr, "%X-%X-%X-%X-%X\n",
        (((char*)&(header->type     ))-((char*)&(header->type))),
        (((char*)&(header->length   ))-((char*)&(header->type))),
        (((char*)&(header->c2spd    ))-((char*)&(header->type))),
        (((char*)&(header->samplename))-((char*)&(header->type))),
        (((char*)&(header->samplesig))-((char*)&(header->type)))
        );

        fprintf(stderr, "Considering %d byte sample (%.4s), %d\n",
        (int)length,
        header->samplesig,
        header->length);
        */
        if(length < 0x50)
                return 0; // too small
        if (strncmp(header->samplesig, "SCRS", 4) != 0
            && strncmp(header->samplesig, "SCRI", 4) != 0)
                return 0; // It should be either SCRS or SCRI.

        size_t samp_length = bswapLE32(header->length);
        int bytes_per_sample = (header->type == 1 ? ((header->flags & 2) ? 2 : 1) : 0); // no sample data

        if (length < 0x50 + smp->length * bytes_per_sample)
                return 0;

        smp->length = samp_length;
        smp->global_volume = 64;
        smp->volume = header->volume*256/64;
        smp->loop_start = header->loopbeg;
        smp->loop_end = header->loopend;
        smp->c5speed = header->c2spd;
        smp->flags = 0;
        if (header->flags & 1)
                smp->flags |= CHN_LOOP;
        if (header->flags & 2)
                smp->flags |= CHN_STEREO;
        if (header->flags & 4)
                smp->flags |= CHN_16BIT;

        if (header->type == 2) {
                smp->flags |= CHN_ADLIB;
                smp->flags &= ~(CHN_LOOP|CHN_16BIT);

                memcpy(smp->adlib_bytes, &header->length, 11);

                smp->length = 1;
                smp->loop_start = 0;
                smp->loop_end = 0;

                smp->data = csf_allocate_sample(1);
        }

        int format = SF_M | SF_LE; // endianness; channels
        format |= (smp->flags & CHN_16BIT) ? (SF_16 | SF_PCMS) : (SF_8 | SF_PCMU); // bits; encoding

        csf_read_sample((song_sample_t *) smp, format,
                (const char *) (data + 0x50), (uint32_t) (length - 0x50));

        strncpy(smp->filename, header->dosfn, 11);
        strncpy(smp->name, header->samplename, 25);

        return 1;
}
Пример #2
0
int fmt_s3m_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
{
        uint16_t nsmp, nord, npat;
        int misc = S3M_UNSIGNED | S3M_CHANPAN; // temporary flags, these are both generally true
        int n;
        song_note_t *note;
        /* junk variables for reading stuff into */
        uint16_t tmp;
        uint8_t c;
        uint32_t tmplong;
        uint8_t b[4];
        /* parapointers */
        uint16_t para_smp[MAX_SAMPLES];
        uint16_t para_pat[MAX_PATTERNS];
        uint32_t para_sdata[MAX_SAMPLES] = { 0 };
        uint32_t smp_flags[MAX_SAMPLES] = { 0 };
        song_sample_t *sample;
        uint16_t trkvers;
        uint16_t flags;
        uint16_t special;
        uint32_t adlib = 0; // bitset
        int uc;
        const char *tid = NULL;

        /* check the tag */
        slurp_seek(fp, 44, SEEK_SET);
        slurp_read(fp, b, 4);
        if (memcmp(b, "SCRM", 4) != 0)
                return LOAD_UNSUPPORTED;

        /* read the title */
        slurp_rewind(fp);
        slurp_read(fp, song->title, 25);
        song->title[25] = 0;

        /* skip the last three bytes of the title, the supposed-to-be-0x1a byte,
        the tracker ID, and the two useless reserved bytes */
        slurp_seek(fp, 7, SEEK_CUR);

        slurp_read(fp, &nord, 2);
        slurp_read(fp, &nsmp, 2);
        slurp_read(fp, &npat, 2);
        nord = bswapLE16(nord);
        nsmp = bswapLE16(nsmp);
        npat = bswapLE16(npat);

        if (nord > MAX_ORDERS || nsmp > MAX_SAMPLES || npat > MAX_PATTERNS)
                return LOAD_FORMAT_ERROR;

        song->flags = SONG_ITOLDEFFECTS;
        slurp_read(fp, &flags, 2);  /* flags (don't really care) */
        flags = bswapLE16(flags);
        slurp_read(fp, &trkvers, 2);
        trkvers = bswapLE16(trkvers);
        slurp_read(fp, &tmp, 2);  /* file format info */
        if (tmp == bswapLE16(1))
                misc &= ~S3M_UNSIGNED;     /* signed samples (ancient s3m) */

        slurp_seek(fp, 4, SEEK_CUR); /* skip the tag */

        song->initial_global_volume = slurp_getc(fp) << 1;
        // In the case of invalid data, ST3 uses the speed/tempo value that's set in the player prior to
        // loading the song, but that's just crazy.
        song->initial_speed = slurp_getc(fp) ?: 6;
        song->initial_tempo = slurp_getc(fp);
        if (song->initial_tempo <= 32) {
                // (Yes, 32 is ignored by Scream Tracker.)
                song->initial_tempo = 125;
        }
        song->mixing_volume = slurp_getc(fp);
        if (song->mixing_volume & 0x80) {
                song->mixing_volume ^= 0x80;
        } else {
                song->flags |= SONG_NOSTEREO;
        }
        uc = slurp_getc(fp); /* ultraclick removal (useless) */

        if (slurp_getc(fp) != 0xfc)
                misc &= ~S3M_CHANPAN;     /* stored pan values */

        /* Interesting: Impulse Tracker appears to leave some junk data in this unused section, and what's
        more, it always seems to follow the same general pattern. So it's actually possible to identify
        whether a song was saved in IT, then loaded and re-saved in ST3. */
        slurp_seek(fp, 8, SEEK_CUR);
        slurp_read(fp, &special, 2); // field not used by st3
        special = bswapLE16(special);

        /* channel settings */
        for (n = 0; n < 32; n++) {
                /* Channel 'type': 0xFF is a disabled channel, which shows up as (--) in ST3.
                Any channel with the high bit set is muted.
                00-07 are L1-L8, 08-0F are R1-R8, 10-18 are adlib channels A1-A9.
                Hacking at a file with a hex editor shows some perhaps partially-implemented stuff:
                types 19-1D show up in ST3 as AB, AS, AT, AC, and AH; 20-2D are the same as 10-1D
                except with 'B' insted of 'A'. None of these appear to produce any sound output,
                apart from 19 which plays adlib instruments briefly before cutting them. (Weird!)
                Also, 1E/1F and 2E/2F display as "??"; and pressing 'A' on a disabled (--) channel
                will change its type to 1F.
                Values past 2F seem to display bits of the UI like the copyright and help, strange!
                These out-of-range channel types will almost certainly hang or crash ST3 or
                produce other strange behavior. Simply put, don't do it. :) */
                c = slurp_getc(fp);
                if (c & 0x80) {
                        song->channels[n].flags |= CHN_MUTE;
                        // ST3 doesn't even play effects in muted channels -- throw them out?
                        c &= ~0x80;
                }
                if (c < 0x08) {
                        // L1-L8 (panned to 3 in ST3)
                        song->channels[n].panning = 14;
                } else if (c < 0x10) {
                        // R1-R8 (panned to C in ST3)
                        song->channels[n].panning = 50;
                } else if (c < 0x19) {
                        // A1-A9
                        song->channels[n].panning = 32;
                        adlib |= 1 << n;
                } else {
                        // Disabled 0xff/0x7f, or broken
                        song->channels[n].panning = 32;
                        song->channels[n].flags |= CHN_MUTE;
                }
                song->channels[n].volume = 64;
        }
        for (; n < 64; n++) {
                song->channels[n].panning = 32;
                song->channels[n].volume = 64;
                song->channels[n].flags = CHN_MUTE;
        }

        /* orderlist */
        slurp_read(fp, song->orderlist, nord);
        memset(song->orderlist + nord, ORDER_LAST, MAX_ORDERS - nord);

        /* load the parapointers */
        slurp_read(fp, para_smp, 2 * nsmp);
        slurp_read(fp, para_pat, 2 * npat);

        /* default pannings */
        if (misc & S3M_CHANPAN) {
                for (n = 0; n < 32; n++) {
                        c = slurp_getc(fp);
                        if (c & 0x20)
                                song->channels[n].panning = ((c & 0xf) << 2) + 2;
                }
        }

        //mphack - fix the pannings
        for (n = 0; n < 64; n++)
                song->channels[n].panning *= 4;

        /* samples */
        for (n = 0, sample = song->samples + 1; n < nsmp; n++, sample++) {
                uint8_t type;

                slurp_seek(fp, (para_smp[n]) << 4, SEEK_SET);

                type = slurp_getc(fp);
                slurp_read(fp, sample->filename, 12);
                sample->filename[12] = 0;

                slurp_read(fp, b, 3); // data pointer for pcm, irrelevant otherwise
                switch (type) {
                case S3I_TYPE_PCM:
                        para_sdata[n] = b[1] | (b[2] << 8) | (b[0] << 16);
                        slurp_read(fp, &tmplong, 4);
                        sample->length = bswapLE32(tmplong);
                        slurp_read(fp, &tmplong, 4);
                        sample->loop_start = bswapLE32(tmplong);
                        slurp_read(fp, &tmplong, 4);
                        sample->loop_end = bswapLE32(tmplong);
                        sample->volume = slurp_getc(fp) * 4; //mphack
                        slurp_getc(fp);      /* unused byte */
                        slurp_getc(fp);      /* packing info (never used) */
                        c = slurp_getc(fp);  /* flags */
                        if (c & 1)
                                sample->flags |= CHN_LOOP;
                        smp_flags[n] = (SF_LE
                                | ((misc & S3M_UNSIGNED) ? SF_PCMU : SF_PCMS)
                                | ((c & 4) ? SF_16 : SF_8)
                                | ((c & 2) ? SF_SS : SF_M));
                        break;

                default:
                        //printf("s3m: mystery-meat sample type %d\n", type);
                case S3I_TYPE_NONE:
                        slurp_seek(fp, 12, SEEK_CUR);
                        sample->volume = slurp_getc(fp) * 4; //mphack
                        slurp_seek(fp, 3, SEEK_CUR);
                        break;

                case S3I_TYPE_ADMEL:
                        slurp_read(fp, sample->adlib_bytes, 12);
                        sample->volume = slurp_getc(fp) * 4; //mphack
                        // next byte is "dsk", what is that?
                        slurp_seek(fp, 3, SEEK_CUR);
                        sample->flags |= CHN_ADLIB;
                        // dumb hackaround that ought to some day be fixed:
                        sample->length = 1;
                        sample->data = csf_allocate_sample(1);
                        break;
                }

                slurp_read(fp, &tmplong, 4);
                sample->c5speed = bswapLE32(tmplong);
                if (type == S3I_TYPE_ADMEL) {
                        if (sample->c5speed < 1000 || sample->c5speed > 0xFFFF) {
                                sample->c5speed = 8363;
                        }
                }
                slurp_seek(fp, 12, SEEK_CUR);        /* wasted space */
                slurp_read(fp, sample->name, 25);
                sample->name[25] = 0;
                sample->vib_type = 0;
                sample->vib_rate = 0;
                sample->vib_depth = 0;
                sample->vib_speed = 0;
                sample->global_volume = 64;
        }

        /* sample data */
        if (!(lflags & LOAD_NOSAMPLES)) {
                for (n = 0, sample = song->samples + 1; n < nsmp; n++, sample++) {
                        if (!sample->length || (sample->flags & CHN_ADLIB))
                                continue;
                        slurp_seek(fp, para_sdata[n] << 4, SEEK_SET);
                        csf_read_sample(sample, smp_flags[n], fp->data + fp->pos, fp->length - fp->pos);
                }
        }

        if (!(lflags & LOAD_NOPATTERNS)) {
                for (n = 0; n < npat; n++) {
                        int row = 0;
                        long end;

                        para_pat[n] = bswapLE16(para_pat[n]);
                        if (!para_pat[n])
                                continue;

                        slurp_seek(fp, para_pat[n] << 4, SEEK_SET);
                        slurp_read(fp, &tmp, 2);
                        end = (para_pat[n] << 4) + bswapLE16(tmp) + 2;

                        song->patterns[n] = csf_allocate_pattern(64);

                        while (row < 64 && slurp_tell(fp) < end) {
                                int mask = slurp_getc(fp);
                                uint8_t chn = (mask & 31);

                                if (mask == EOF) {
                                        log_appendf(4, " Warning: Pattern %d: file truncated", n);
                                        break;
                                }
                                if (!mask) {
                                        /* done with the row */
                                        row++;
                                        continue;
                                }
                                note = song->patterns[n] + 64 * row + chn;
                                if (mask & 32) {
                                        /* note/instrument */
                                        note->note = slurp_getc(fp);
                                        note->instrument = slurp_getc(fp);
                                        //if (note->instrument > 99)
                                        //      note->instrument = 0;
                                        switch (note->note) {
                                        default:
                                                // Note; hi=oct, lo=note
                                                note->note = (note->note >> 4) * 12 + (note->note & 0xf) + 13;
                                                break;
                                        case 255:
                                                note->note = NOTE_NONE;
                                                break;
                                        case 254:
                                                note->note = (adlib & (1 << chn)) ? NOTE_OFF : NOTE_CUT;
                                                break;
                                        }
                                }
                                if (mask & 64) {
                                        /* volume */
                                        note->voleffect = VOLFX_VOLUME;
                                        note->volparam = slurp_getc(fp);
                                        if (note->volparam == 255) {
                                                note->voleffect = VOLFX_NONE;
                                                note->volparam = 0;
                                        } else if (note->volparam > 64) {
                                                // some weirdly saved s3m?
                                                note->volparam = 64;
                                        }
                                }
                                if (mask & 128) {
                                        note->effect = slurp_getc(fp);
                                        note->param = slurp_getc(fp);
                                        csf_import_s3m_effect(note, 0);
                                        if (note->effect == FX_SPECIAL) {
                                                // mimic ST3's SD0/SC0 behavior
                                                if (note->param == 0xd0) {
                                                        note->note = NOTE_NONE;
                                                        note->instrument = 0;
                                                        note->voleffect = VOLFX_NONE;
                                                        note->volparam = 0;
                                                        note->effect = FX_NONE;
                                                        note->param = 0;
                                                } else if (note->param == 0xc0) {
                                                        note->effect = FX_NONE;
                                                        note->param = 0;
                                                }
                                        }
                                }
                                /* ... next note, same row */
                        }
                }
        }
Пример #3
0
int load_its_sample(const uint8_t *header, const uint8_t *data, size_t length, song_sample_t *smp)
{
        struct it_sample *its = (struct it_sample *)header;
        uint32_t format;
        uint32_t bp;

        if (length < 80 || strncmp((const char *) header, "IMPS", 4) != 0)
                return 0;
        /* alright, let's get started */
        smp->length = bswapLE32(its->length);
        if ((its->flags & 1) == 0) {
                // sample associated with header
                return 0;
        }

        // endianness (always little)
        format = SF_LE;
        if (its->flags & 8) {
                // no such thing as compressed stereo
                // (TODO perhaps test with various players to see how this is implemented)
                format |= SF_M;
                // compression algorithm
                format |= (its->cvt & 4) ? SF_IT215 : SF_IT214;
        } else {
                // channels
                format |= (its->flags & 4) ? SF_SS : SF_M;
                // signedness (or delta?)
                format |= (its->cvt & 4) ? SF_PCMD : (its->cvt & 1) ? SF_PCMS : SF_PCMU;
        }
        // bit width
        format |= (its->flags & 2) ? SF_16 : SF_8;

        smp->global_volume = its->gvl;
        if (its->flags & 16) {
                smp->flags |= CHN_LOOP;
                if (its->flags & 64)
                        smp->flags |= CHN_PINGPONGLOOP;
        }
        if (its->flags & 32) {
                smp->flags |= CHN_SUSTAINLOOP;
                if (its->flags & 128)
                        smp->flags |= CHN_PINGPONGSUSTAIN;
        }
        smp->volume = its->vol * 4;
        strncpy(smp->name, (const char *) its->name, 25);
        smp->panning = (its->dfp & 127) * 4;
        if (its->dfp & 128)
                smp->flags |= CHN_PANNING;
        smp->loop_start = bswapLE32(its->loopbegin);
        smp->loop_end = bswapLE32(its->loopend);
        smp->c5speed = bswapLE32(its->C5Speed);
        smp->sustain_start = bswapLE32(its->susloopbegin);
        smp->sustain_end = bswapLE32(its->susloopend);

        int vibs[] = {VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_RANDOM};
        smp->vib_type = vibs[its->vit & 3];
        smp->vib_rate = its->vir;
        smp->vib_depth = its->vid;
        smp->vib_speed = its->vis;

        // sanity checks
        // (I should probably have more of these in general)
        if (smp->loop_start > smp->length) {
                smp->loop_start = smp->length;
                smp->flags &= ~(CHN_LOOP | CHN_PINGPONGLOOP);
        }
        if (smp->loop_end > smp->length) {
                smp->loop_end = smp->length;
                smp->flags &= ~(CHN_LOOP | CHN_PINGPONGLOOP);
        }
        if (smp->sustain_start > smp->length) {
                smp->sustain_start = smp->length;
                smp->flags &= ~(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
        }
        if (smp->sustain_end > smp->length) {
                smp->sustain_end = smp->length;
                smp->flags &= ~(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
        }

        bp = bswapLE32(its->samplepointer);

        // dumb casts :P
        return csf_read_sample((song_sample_t *) smp, format,
                        (const char *) (data + bp),
                        (uint32_t) (length - bp));
}
Пример #4
0
int fmt_pat_load_instrument(const uint8_t *data, size_t length, int slot)
{
        struct GF1PatchHeader header;
        struct GF1PatchSampleHeader gfsamp;
        struct instrumentloader ii;
        song_instrument_t *g;
        song_sample_t *smp;
        unsigned int pos, rs;
        int lo, hi, tmp, i, nsamp, n;

        if (length < sizeof(header) || !slot) return 0;
        memcpy(&header, data, sizeof(header));
        if ((memcmp(header.sig, "GF1PATCH", 8) != 0)
            || (memcmp(header.ver, "110\0", 4) != 0 && memcmp(header.ver, "100\0", 4) != 0)
            || (memcmp(header.id, "ID#000002\0", 10) != 0)) {
                return 0;
        }

        header.waveforms = bswapLE16(header.waveforms);
        header.mastervol = bswapLE16(header.mastervol);
        header.datasize  = bswapLE32(header.datasize);
        header.insID     = bswapLE16(header.insID);
        header.inssize   = bswapLE32(header.inssize);
        header.layersize = bswapLE32(header.layersize);

        g = instrument_loader_init(&ii, slot);
        memcpy(g->name, header.insname, 16);
        g->name[15] = '\0';

        nsamp = CLAMP(header.smpnum, 1, 16);
        pos = sizeof(header);
        for (i = 0; i < 120; i++) {
                g->sample_map[i] = 0;
                g->note_map[i] = i + 1;
        }
        for (i = 0; i < nsamp; i++) {
                memcpy(&gfsamp, data + pos, sizeof(gfsamp));
                pos += sizeof(gfsamp);

                n = instrument_loader_sample(&ii, i + 1) - 1;
                smp = song_get_sample(n);

                gfsamp.samplesize = bswapLE32(gfsamp.samplesize);
                gfsamp.loopstart = bswapLE32(gfsamp.loopstart);
                gfsamp.loopend = bswapLE32(gfsamp.loopend);
                gfsamp.samplerate = bswapLE16(gfsamp.samplerate);
                gfsamp.lofreq = bswapLE32(gfsamp.lofreq);
                gfsamp.hifreq = bswapLE32(gfsamp.hifreq);
                gfsamp.rtfreq = bswapLE32(gfsamp.rtfreq);
                gfsamp.tune = bswapLE16(gfsamp.tune);
                gfsamp.scalefreq = bswapLE16(gfsamp.scalefac);

                lo = CLAMP(gusfreq(gfsamp.lofreq), 0, 95);
                hi = CLAMP(gusfreq(gfsamp.hifreq), 0, 95);
                if (lo > hi) {
                        tmp = lo;
                        lo = hi;
                        hi = tmp;
                }
                for (; lo < hi; lo++) {
                        g->sample_map[lo + 12] = n;
                }

                if (gfsamp.smpmode & 1) {
                        gfsamp.samplesize >>= 1;
                        gfsamp.loopstart >>= 1;
                        gfsamp.loopend >>= 1;
                }
                smp->length = gfsamp.samplesize;
                smp->loop_start = smp->sustain_start = gfsamp.loopstart;
                smp->loop_end = smp->sustain_end = gfsamp.loopend;
                smp->c5speed = gfsamp.samplerate;

                smp->flags = 0;
                rs = SF_M | SF_LE; // channels; endianness
                rs |= (gfsamp.smpmode & 1) ? SF_16 : SF_8; // bit width
                rs |= (gfsamp.smpmode & 2) ? SF_PCMU : SF_PCMS; // encoding
                if (gfsamp.smpmode & 32) {
                        if (gfsamp.smpmode & 4)
                                smp->flags |= CHN_SUSTAINLOOP;
                        if (gfsamp.smpmode & 8)
                                smp->flags |= CHN_PINGPONGSUSTAIN;
                } else {
                        if (gfsamp.smpmode & 4)
                                smp->flags |= CHN_LOOP;
                        if (gfsamp.smpmode & 8)
                                smp->flags |= CHN_PINGPONGLOOP;
                }
                memcpy(smp->filename, gfsamp.wavename, 7);
                smp->filename[8] = '\0';
                strcpy(smp->name, smp->filename);
                smp->vib_speed = gfsamp.vib_speed;
                smp->vib_rate = gfsamp.vib_rate;
                smp->vib_depth = gfsamp.vib_depth;

                pos += csf_read_sample(current_song->samples + n, rs, data + pos, length - pos);
        }
Пример #5
0
static int _read_iff(dmoz_file_t *file, song_sample_t *smp, const uint8_t *data, size_t length)
{
        chunk_t chunk;
        size_t pos = 0;
        chunk_t vhdr, body, name, comm, auth, anno, ssnd; // butt

        if (!iff_chunk_read(&chunk, data, length, &pos))
                return 0;
        if (chunk.id != ID_FORM)
                return 0;

        // jump "into" the FORM chunk
        // if (pos < length), there's more data after the FORM chunk -- but I don't care about this scenario
        pos = 0;
        length = MIN(length, chunk.size);
        data = chunk.data->FORM.data;

        /* the header is already byteswapped, but anything in 'chunk' will need to be swapped as needed
        because the structure is a const pointing into the data itself */
        switch (bswapBE32(chunk.data->FORM.filetype)) {
        case ID_8SVX:
                // shut up, gcc
                ZEROIZE(vhdr);
                ZEROIZE(body);
                ZEROIZE(name);
                ZEROIZE(auth);
                ZEROIZE(anno);

                while (iff_chunk_read(&chunk, data, length, &pos)) {
                        switch (chunk.id) {
                                case ID_VHDR: vhdr = chunk; break;
                                case ID_BODY: body = chunk; break;
                                case ID_NAME: name = chunk; break;
                                case ID_AUTH: auth = chunk; break;
                                case ID_ANNO: anno = chunk; break;
                                default: break;
                        }
                }
                if (!(vhdr.id && body.id))
                        return 0;

                if (vhdr.data->VHDR.compression) {
                        log_appendf(4, "error: compressed 8SVX files are unsupported");
                        return 0;
                }
                if (vhdr.data->VHDR.num_octaves != 1) {
                        log_appendf(4, "warning: 8SVX file contains %d octaves",
                                vhdr.data->VHDR.num_octaves);
                }

                if (file) {
                        file->description = "8SVX sample";
                        file->type = TYPE_SAMPLE_PLAIN;
                }
                if (!name.id) name = auth;
                if (!name.id) name = anno;
                if (name.id) {
                        if (file) {
                                file->title = calloc(1, name.size + 1);
                                memcpy(file->title, name.data->bytes, name.size);
                                file->title[name.size] = '\0';
                        }
                        if (smp) {
                                int len = MIN(25, name.size);
                                memcpy(smp->name, name.data->bytes, len);
                                smp->name[len] = 0;
                        }
                }

                if (smp) {
                        smp->c5speed = bswapBE16(vhdr.data->VHDR.smp_per_sec);
                        smp->length = body.size;

                        csf_read_sample(smp, SF_BE | SF_PCMS | SF_8 | SF_M, body.data->bytes, body.size);

                        smp->volume = 64*4;
                        smp->global_volume = 64;

                        // this is done kinda weird
                        smp->loop_end = bswapBE32(vhdr.data->VHDR.smp_highoct_repeat);
                        if (smp->loop_end) {
                                smp->loop_start = bswapBE32(vhdr.data->VHDR.smp_highoct_1shot);
                                smp->loop_end += smp->loop_start;
                                if (smp->loop_start > smp->length)
                                        smp->loop_start = 0;
                                if (smp->loop_end > smp->length)
                                        smp->loop_end = smp->length;
                                if (smp->loop_start + 2 < smp->loop_end)
                                        smp->flags |= CHN_LOOP;
                        }
                        // TODO vhdr.data->VHDR.volume ?
                }

                return 1;

        case ID_AIFF:
                ZEROIZE(comm);
                ZEROIZE(ssnd);
                ZEROIZE(name);
                ZEROIZE(auth);
                ZEROIZE(anno);

                while (iff_chunk_read(&chunk, data, length, &pos)) {
                        switch (chunk.id) {
                                case ID_COMM: comm = chunk; break;
                                case ID_SSND: ssnd = chunk; break;
                                case ID_NAME: name = chunk; break;
                                default: break;
                        }
                }
                if (!(comm.id && ssnd.id))
                        return 0;

                if (file) {
                        file->description = "Audio IFF sample";
                        file->type = TYPE_SAMPLE_PLAIN;
                }
                if (!name.id) name = auth;
                if (!name.id) name = anno;
                if (name.id) {
                        if (file) {
                                file->title = calloc(1, name.size + 1);
                                memcpy(file->title, name.data->bytes, name.size);
                                file->title[name.size] = '\0';
                        }
                        if (smp) {
                                int len = MIN(25, name.size);
                                memcpy(smp->name, name.data->bytes, len);
                                smp->name[len] = 0;
                        }
                }

                /* TODO loop points */

                if (smp) {
                        uint32_t flags = SF_BE | SF_PCMS;

                        switch (bswapBE16(comm.data->COMM.num_channels)) {
                        default:
                                log_appendf(4, "warning: multichannel AIFF is unsupported");
                        case 1:
                                flags |= SF_M;
                                break;
                        case 2:
                                flags |= SF_SI;
                                break;
                        }

                        switch ((bswapBE16(comm.data->COMM.sample_size) + 7) & ~7) {
                        default:
                                log_appendf(4, "warning: AIFF has unsupported bit-width");
                        case 8:
                                flags |= SF_8;
                                break;
                        case 16:
                                flags |= SF_16;
                                break;
                        }

                        // TODO: data checking; make sure sample count and byte size agree
                        // (and if not, cut to shorter of the two)

                        smp->c5speed = ConvertFromIeeeExtended(comm.data->COMM.sample_rate);
                        smp->length = bswapBE32(comm.data->COMM.num_frames);
                        smp->volume = 64*4;
                        smp->global_volume = 64;

                        // the audio data starts 8 bytes into the chunk
                        // (don't care about the block alignment stuff)
                        csf_read_sample(smp, flags, ssnd.data->bytes + 8, ssnd.size - 8);
                }

                return 1;
        }

        return 0;
}
Пример #6
0
int fmt_mod_load_song(song_t *song, slurp_t *fp, unsigned int lflags)
{
	uint8_t tag[4];
	int n, npat, pat, chan, nchan, nord;
	song_note_t *note;
	uint16_t tmp;
	int startrekker = 0;
	int test_wow = 0;
	int mk = 0;
	int maybe_st3 = 0;
	int maybe_ft2 = 0;
	uint8_t restart;
	long samplesize = 0;
	const char *tid = NULL;

	/* check the tag (and set the number of channels) -- this is ugly, so don't look */
	slurp_seek(fp, 1080, SEEK_SET);
	slurp_read(fp, tag, 4);
	if (!memcmp(tag, "M.K.", 4)) {
		/* M.K. = Protracker etc., or Mod's Grave (*.wow) */
		nchan = 4;
		test_wow = 1;
		mk = 1;
		maybe_ft2 = 1;
		tid = "Amiga-NewTracker";
	} else if (!memcmp(tag, "M!K!", 4)) {
		nchan = 4;
		tid = "Amiga-ProTracker";
	} else if (!memcmp(tag, "M&K!", 4) || !memcmp(tag, "N.T.", 4)) {
		nchan = 4;
		tid = "Amiga-NoiseTracker"; // or so the word on the street is; I don't have any of these
	} else if ((!memcmp(tag, "FLT", 3) || !memcmp(tag, "EXO", 3)) && (tag[3] == '4' || tag[3] == '8')) {
		// Hopefully EXO8 is stored the same way as FLT8
		nchan = tag[3] - '0';
		startrekker = (nchan == 8);
		tid = "%d Channel Startrekker";
		//log_appendf(4, " Warning: Startrekker AM synth is not supported");
	} else if (!memcmp(tag, "FEST", 4)) {
		// the mysterious mod.jobbig
		nchan = 4;
		tid = "4 Channel Startrekker (?)";
	} else if (!memcmp(tag, "OCTA", 4)) {
		nchan = 8;
		tid = "Amiga Oktalyzer"; // IT just identifies this as "8 Channel MOD"
	} else if (!memcmp(tag, "CD81", 4)) {
		nchan = 8;
		tid = "8 Channel Falcon"; // Atari Oktalyser
	} else if (tag[0] > '0' && tag[0] <= '9' && !memcmp(tag + 1, "CHN", 3)) {
		/* nCHN = Fast Tracker (if n is even) or TakeTracker (if n = 5, 7, or 9) */
		nchan = tag[0] - '0';
		if (nchan == 5 || nchan == 7 || nchan == 9) {
			tid = "%d Channel TakeTracker";
		} else {
			if (!(nchan & 1))
				maybe_ft2 = 1;
			tid = "%d Channel MOD"; // generic
		}
		maybe_st3 = 1;
	} else if (tag[0] > '0' && tag[0] <= '9' && tag[1] >= '0' && tag[1] <= '9'
		   && tag[2] == 'C' && (tag[3] == 'H' || tag[3] == 'N')) {
		/* nnCH = Fast Tracker (if n is even and <= 32) or TakeTracker (if n = 11, 13, 15)
		 * Not sure what the nnCN variant is. */
		nchan = 10 * (tag[0] - '0') + (tag[1] - '0');
		if (nchan == 11 || nchan == 13 || nchan == 15) {
			tid = "%d Channel TakeTracker";
		} else {
			if ((nchan & 1) == 0 && nchan <= 32 && tag[3] == 'H')
				maybe_ft2 = 1;
			tid = "%d Channel MOD"; // generic
		}
		if (tag[3] == 'H')
			maybe_st3 = 1;
	} else if (!memcmp(tag, "TDZ", 3) && tag[3] > '0' && tag[3] <= '9') {
		/* TDZ[1-3] = TakeTracker */
		nchan = tag[3] - '0';
		if (nchan < 4)
			tid = "%d Channel TakeTracker";
		else
			tid = "%d Channel MOD";
	} else {
		return LOAD_UNSUPPORTED;
	}

	/* suppose the tag is 90CH :) */
	if (nchan > 64) {
		//fprintf(stderr, "%s: Too many channels!\n", filename);
		return LOAD_FORMAT_ERROR;
	}

	/* read the title */
	slurp_rewind(fp);
	slurp_read(fp, song->title, 20);
	song->title[20] = 0;

	/* sample headers */
	for (n = 1; n < 32; n++) {
		slurp_read(fp, song->samples[n].name, 22);
		song->samples[n].name[22] = 0;

		slurp_read(fp, &tmp, 2);
		song->samples[n].length = bswapBE16(tmp) * 2;

		/* this is only necessary for the wow test... */
		samplesize += song->samples[n].length;

		song->samples[n].c5speed = MOD_FINETUNE(slurp_getc(fp));

		song->samples[n].volume = slurp_getc(fp);
		if (song->samples[n].volume > 64)
			song->samples[n].volume = 64;
		if (!song->samples[n].length && song->samples[n].volume)
			maybe_ft2 = 0;
		song->samples[n].volume *= 4; //mphack
		song->samples[n].global_volume = 64;

		slurp_read(fp, &tmp, 2);
		song->samples[n].loop_start = bswapBE16(tmp) * 2;
		slurp_read(fp, &tmp, 2);
		tmp = bswapBE16(tmp) * 2;
		if (tmp > 2)
			song->samples[n].flags |= CHN_LOOP;
		else if (tmp == 0)
			maybe_st3 = 0;
		else if (!song->samples[n].length)
			maybe_ft2 = 0;
		song->samples[n].loop_end = song->samples[n].loop_start + tmp;
		song->samples[n].vib_type = 0;
		song->samples[n].vib_rate = 0;
		song->samples[n].vib_depth = 0;
		song->samples[n].vib_speed = 0;
	}

	/* pattern/order stuff */
	nord = slurp_getc(fp);
	restart = slurp_getc(fp);

	slurp_read(fp, song->orderlist, 128);
	npat = 0;
	if (startrekker) {
		/* from mikmod: if the file says FLT8, but the orderlist
		has odd numbers, it's probably really an FLT4 */
		for (n = 0; n < 128; n++) {
			if (song->orderlist[n] & 1) {
				startrekker = 0;
				nchan = 4;
				break;
			}
		}
	}
	if (startrekker) {
		for (n = 0; n < 128; n++)
			song->orderlist[n] >>= 1;
	}
	for (n = 0; n < 128; n++) {
		if (song->orderlist[n] >= MAX_PATTERNS)
			song->orderlist[n] = ORDER_SKIP;
		else if (song->orderlist[n] > npat)
			npat = song->orderlist[n];
	}
	/* set all the extra orders to the end-of-song marker */
	memset(song->orderlist + nord, ORDER_LAST, MAX_ORDERS - nord);

	if (restart == 0x7f && maybe_st3)
		tid = "Scream Tracker 3?";
	else if (restart == 0x7f && mk)
		tid = "%d Channel ProTracker";
	else if (restart <= npat && maybe_ft2)
		tid = "%d Channel FastTracker";
	else if (restart == npat && mk)
		tid = "%d Channel Soundtracker";

	/* hey, is this a wow file? */
	if (test_wow) {
		slurp_seek(fp, 0, SEEK_END);
		if (slurp_tell(fp) == 2048 * npat + samplesize + 3132) {
			nchan = 8;
			tid = "Mod's Grave WOW";
		}
	}


	// http://llvm.org/viewvc/llvm-project?view=rev&revision=91888
	sprintf(song->tracker_id, tid ? tid : "%d Channel MOD", nchan);
	slurp_seek(fp, 1084, SEEK_SET);

	/* pattern data */
	if (startrekker) {
		for (pat = 0; pat <= npat; pat++) {
			note = song->patterns[pat] = csf_allocate_pattern(64);
			song->pattern_size[pat] = song->pattern_alloc_size[pat] = 64;
			for (n = 0; n < 64; n++, note += 60) {
				for (chan = 0; chan < 4; chan++, note++) {
					uint8_t p[4];
					slurp_read(fp, p, 4);
					mod_import_note(p, note);
					csf_import_mod_effect(note, 0);
				}
			}
			note = song->patterns[pat] + 4;
			for (n = 0; n < 64; n++, note += 60) {
				for (chan = 0; chan < 4; chan++, note++) {
					uint8_t p[4];
					slurp_read(fp, p, 4);
					mod_import_note(p, note);
					csf_import_mod_effect(note, 0);
				}
			}
		}
	} else {
		for (pat = 0; pat <= npat; pat++) {
			note = song->patterns[pat] = csf_allocate_pattern(64);
			song->pattern_size[pat] = song->pattern_alloc_size[pat] = 64;
			for (n = 0; n < 64; n++, note += 64 - nchan) {
				for (chan = 0; chan < nchan; chan++, note++) {
					uint8_t p[4];
					slurp_read(fp, p, 4);
					mod_import_note(p, note);
					csf_import_mod_effect(note, 0);
				}
			}
		}
	}
	if (restart < npat)
		csf_insert_restart_pos(song, restart);

	/* sample data */
	if (!(lflags & LOAD_NOSAMPLES)) {
		for (n = 1; n < 32; n++) {
			uint32_t ssize;

			if (song->samples[n].length == 0)
				continue;
			ssize = csf_read_sample(song->samples + n, SF_8 | SF_M | SF_LE | SF_PCMS,
				fp->data + fp->pos, fp->length - fp->pos);
			slurp_seek(fp, ssize, SEEK_CUR);
		}
	}

	/* set some other header info that's always the same for .mod files */
	song->flags = (SONG_ITOLDEFFECTS | SONG_COMPATGXX);
	for (n = 0; n < nchan; n++)
		song->channels[n].panning = PROTRACKER_PANNING(n);
	for (; n < MAX_CHANNELS; n++)
		song->channels[n].flags = CHN_MUTE;

	song->pan_separation = 64;

//      if (slurp_error(fp)) {
//              return LOAD_FILE_ERROR;
//      }

	/* done! */
	return LOAD_SUCCESS;
}