/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read an old Protracker / / \ \ * Studio module from an open file. | < / \_ * | \/ /\ / * By Christopher Snowhill. \_ / > / * | \ / / * | ' / * \__/ */ #include <stdlib.h>#include <string.h>#include <math.h> #include "dumb.h"#include "internal/it.h" static int psm_sample_compare(const void *e1, const void *e2) { const unsigned char *pa = e1; const unsigned char *pb = e2; int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24); int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24); return a - b;} static int it_old_psm_read_samples(IT_SAMPLE **sample, DUMBFILE *f, int *num) { int n, o, count = *num, true_num, snum, offset, flags, finetune, delta; unsigned char *buffer; const unsigned char *sdata; long sample_bytes; buffer = malloc(count * 64); if (!buffer) goto error; if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb; true_num = 0; for (n = 0; n < count; n++) { snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); if ((snum < 1) || (snum > 255)) goto error_fb; if (true_num < snum) true_num = snum; } if (true_num > count) { IT_SAMPLE *meh = realloc(*sample, true_num * sizeof(*meh)); if (!meh) goto error_fb; for (n = count; n < true_num; n++) { meh[n].data = NULL; } *sample = meh; *num = true_num; } qsort(buffer, count, 64, psm_sample_compare); for (n = 0; n < *num; n++) { (*sample)[n].flags = 0; } for (n = 0; n < count; n++) { IT_SAMPLE smp; IT_SAMPLE *s; snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); s = &((*sample)[snum - 1]); memcpy(smp.filename, buffer + (n * 64), 13); smp.filename[13] = 0; memcpy(smp.name, buffer + (n * 64) + 13, 24); smp.name[24] = 0; offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) | (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24); flags = buffer[(n * 64) + 47]; smp.length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); smp.loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); smp.loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); if (smp.length <= 0) continue; finetune = buffer[(n * 64) + 60]; smp.default_volume = buffer[(n * 64) + 61]; smp.C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); if (finetune & 15) { finetune &= 15; if (finetune >= 8) finetune -= 16; // s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, // finetune*32)); smp.finetune = finetune * 32; } else smp.finetune = 0; smp.flags = IT_SAMPLE_EXISTS; if (flags & 0x41) continue; if (flags & 0x20) smp.flags |= IT_SAMPLE_PINGPONG_LOOP; if (flags & 4) smp.flags |= IT_SAMPLE_16BIT; if (flags & 0x80) { smp.flags |= IT_SAMPLE_LOOP; if ((unsigned int)smp.loop_end > (unsigned int)smp.length) smp.loop_end = smp.length; else if ((unsigned int)smp.loop_start >= (unsigned int)smp.loop_end) smp.flags &= ~IT_SAMPLE_LOOP; else smp.length = smp.loop_end; } smp.global_volume = 64; smp.vibrato_speed = 0; smp.vibrato_depth = 0; smp.vibrato_rate = 0; smp.vibrato_waveform = IT_VIBRATO_SINE; smp.max_resampling_quality = -1; sample_bytes = smp.length * ((flags & 4) ? 2 : 1); smp.data = malloc(sample_bytes); if (!smp.data) goto error_fb; sdata = (const unsigned char *)smp.data; if (dumbfile_seek(f, offset, DFS_SEEK_SET) || dumbfile_getnc(smp.data, sample_bytes, f) < sample_bytes) goto error_fd; if (flags & 0x10) { if (flags & 8) { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; } else { for (o = 0; o < smp.length; o++) ((signed char *)smp.data)[o] = sdata[o] ^ 0x80; } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); } else { memcpy(smp.data, sdata, smp.length); } } } else { delta = 0; if (flags & 8) { /* unsigned delta? mehhh, does anything even use this? */ if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((short *)smp.data)[o] = delta ^ 0x8000; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta ^ 0x80; } } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (signed short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((signed short *)smp.data)[o] = delta; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta; } } } } if (s->data) free(s->data); *s = smp; } free(buffer); return 0; error_fd: free((void *)sdata);error_fb: free(buffer);error: return -1;} static int it_old_psm_read_patterns(IT_PATTERN *pattern, DUMBFILE *f, int num, int size, int pchans) { int n, offset, psize, rows, chans, row, flags, channel; unsigned char *buffer, *ptr, *end; IT_ENTRY *entry; buffer = malloc(size); if (!buffer) goto error; if (dumbfile_getnc((char *)buffer, size, f) < size) goto error_fb; offset = 0; for (n = 0; n < num; n++) { IT_PATTERN *p = &pattern[n]; if (offset >= size) goto error_fb; ptr = buffer + offset; psize = ptr[0] | (ptr[1] << 8); rows = ptr[2]; chans = ptr[3]; if (!rows || !chans) { p->n_rows = 1; p->n_entries = 0; continue; } psize = (psize + 15) & ~15; if (offset + psize > size) goto error_fb; end = ptr + psize; ptr += 4; p->n_rows = rows; p->n_entries = rows; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { row++; continue; } if (flags & 0xE0) { p->n_entries++; if (flags & 0x80) ptr += 2; if (flags & 0x40) ptr++; if (flags & 0x20) { if (*ptr == 40) ptr += 4; else ptr += 2; } } } entry = malloc(p->n_entries * sizeof(*p->entry)); if (!entry) goto error_fb; p->entry = entry; ptr = buffer + offset + 4; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { IT_SET_END_ROW(entry); entry++; row++; continue; } if (flags & 0xE0) { entry->mask = 0; entry->channel = channel = flags & 0x1F; if (channel >= chans) { // channel = 0; // goto error_fb; } if (flags & 0x80) { if ((*ptr < 60) && (channel < pchans)) { entry->mask |= IT_ENTRY_NOTE; entry->note = *ptr + 35; } ptr++; if (*ptr) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = *ptr; } ptr++; } if (flags & 0x40) { if (*ptr <= 64) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = *ptr; } ptr++; } if (flags & 0x20) { entry->mask |= IT_ENTRY_EFFECT; switch (*ptr) { case 1: entry->effect = IT_XM_FINE_VOLSLIDE_UP; entry->effectvalue = ptr[1]; break; case 2: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = (ptr[1] << 4) & 0xF0; break; case 3: entry->effect = IT_XM_FINE_VOLSLIDE_DOWN; entry->effectvalue = ptr[1]; break; case 4: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = ptr[1] & 0xF; break; case 10: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]); break; case 11: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = ptr[1]; break; case 12: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF); break; case 13: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = ptr[1]; break; case 14: entry->effect = IT_TONE_PORTAMENTO; entry->effectvalue = ptr[1]; break; case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15); break; case 16: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] << 4; break; case 17: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] & 0xF; break; case 20: entry->effect = IT_VIBRATO; entry->effectvalue = ptr[1]; break; case 21: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11); break; case 22: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] << 4; break; case 23: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] & 0xF; break; case 30: entry->effect = IT_TREMOLO; entry->effectvalue = ptr[1]; break; case 31: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11); break; case 40: entry->effect = IT_SET_SAMPLE_OFFSET; entry->effectvalue = ptr[2]; ptr += 2; break; case 41: entry->effect = IT_XM_RETRIGGER_NOTE; entry->effectvalue = ptr[1]; break; case 42: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF); break; case 43: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF); break; case 50: entry->effect = IT_JUMP_TO_ORDER; entry->effectvalue = ptr[1]; break; case 51: entry->effect = IT_BREAK_TO_ROW; entry->effectvalue = ptr[1]; break; case 52: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF); break; case 53: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF); break; case 60: entry->effect = IT_SET_SPEED; entry->effectvalue = ptr[1]; break; case 61: entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = ptr[1]; break; case 70: entry->effect = IT_ARPEGGIO; entry->effectvalue = ptr[1]; break; case 71: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF); break; case 72: /* "balance" ... panning? */ entry->effect = IT_SET_PANNING; entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7; break; default: entry->mask &= ~IT_ENTRY_EFFECT; }Lines 1–500 of 745. Load more
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * readpsm.c - Code to read an old Protracker / / \ \ * Studio module from an open file. | < / \_ * | \/ /\ / * By Christopher Snowhill. \_ / > / * | \ / / * | ' / * \__/ */ #include <stdlib.h> #include <string.h> #include <math.h> #include "dumb.h" #include "internal/it.h" static int psm_sample_compare(const void *e1, const void *e2) { const unsigned char *pa = e1; const unsigned char *pb = e2; int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24); int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24); return a - b; } static int it_old_psm_read_samples(IT_SAMPLE **sample, DUMBFILE *f, int *num) { int n, o, count = *num, true_num, snum, offset, flags, finetune, delta; unsigned char *buffer; const unsigned char *sdata; long sample_bytes; buffer = malloc(count * 64); if (!buffer) goto error; if (dumbfile_getnc((char *)buffer, count * 64, f) < count * 64) goto error_fb; true_num = 0; for (n = 0; n < count; n++) { snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); if ((snum < 1) || (snum > 255)) goto error_fb; if (true_num < snum) true_num = snum; } if (true_num > count) { IT_SAMPLE *meh = realloc(*sample, true_num * sizeof(*meh)); if (!meh) goto error_fb; for (n = count; n < true_num; n++) { meh[n].data = NULL; } *sample = meh; *num = true_num; } qsort(buffer, count, 64, psm_sample_compare); for (n = 0; n < *num; n++) { (*sample)[n].flags = 0; } for (n = 0; n < count; n++) { IT_SAMPLE smp; IT_SAMPLE *s; snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); s = &((*sample)[snum - 1]); memcpy(smp.filename, buffer + (n * 64), 13); smp.filename[13] = 0; memcpy(smp.name, buffer + (n * 64) + 13, 24); smp.name[24] = 0; offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) | (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24); flags = buffer[(n * 64) + 47]; smp.length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); smp.loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); smp.loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); if (smp.length <= 0) continue; finetune = buffer[(n * 64) + 60]; smp.default_volume = buffer[(n * 64) + 61]; smp.C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); if (finetune & 15) { finetune &= 15; if (finetune >= 8) finetune -= 16; // s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, // finetune*32)); smp.finetune = finetune * 32; } else smp.finetune = 0; smp.flags = IT_SAMPLE_EXISTS; if (flags & 0x41) continue; if (flags & 0x20) smp.flags |= IT_SAMPLE_PINGPONG_LOOP; if (flags & 4) smp.flags |= IT_SAMPLE_16BIT; if (flags & 0x80) { smp.flags |= IT_SAMPLE_LOOP; if ((unsigned int)smp.loop_end > (unsigned int)smp.length) smp.loop_end = smp.length; else if ((unsigned int)smp.loop_start >= (unsigned int)smp.loop_end) smp.flags &= ~IT_SAMPLE_LOOP; else smp.length = smp.loop_end; } smp.global_volume = 64; smp.vibrato_speed = 0; smp.vibrato_depth = 0; smp.vibrato_rate = 0; smp.vibrato_waveform = IT_VIBRATO_SINE; smp.max_resampling_quality = -1; sample_bytes = smp.length * ((flags & 4) ? 2 : 1); smp.data = malloc(sample_bytes); if (!smp.data) goto error_fb; sdata = (const unsigned char *)smp.data; if (dumbfile_seek(f, offset, DFS_SEEK_SET) || dumbfile_getnc(smp.data, sample_bytes, f) < sample_bytes) goto error_fd; if (flags & 0x10) { if (flags & 8) { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; } else { for (o = 0; o < smp.length; o++) ((signed char *)smp.data)[o] = sdata[o] ^ 0x80; } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) ((short *)smp.data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); } else { memcpy(smp.data, sdata, smp.length); } } } else { delta = 0; if (flags & 8) { /* unsigned delta? mehhh, does anything even use this? */ if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((short *)smp.data)[o] = delta ^ 0x8000; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta ^ 0x80; } } } else { if (flags & 4) { for (o = 0; o < smp.length; o++) { delta += (signed short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); ((signed short *)smp.data)[o] = delta; } } else { for (o = 0; o < smp.length; o++) { delta += (signed char)sdata[o]; ((signed char *)smp.data)[o] = delta; } } } } if (s->data) free(s->data); *s = smp; } free(buffer); return 0; error_fd: free((void *)sdata); error_fb: free(buffer); error: return -1; } static int it_old_psm_read_patterns(IT_PATTERN *pattern, DUMBFILE *f, int num, int size, int pchans) { int n, offset, psize, rows, chans, row, flags, channel; unsigned char *buffer, *ptr, *end; IT_ENTRY *entry; buffer = malloc(size); if (!buffer) goto error; if (dumbfile_getnc((char *)buffer, size, f) < size) goto error_fb; offset = 0; for (n = 0; n < num; n++) { IT_PATTERN *p = &pattern[n]; if (offset >= size) goto error_fb; ptr = buffer + offset; psize = ptr[0] | (ptr[1] << 8); rows = ptr[2]; chans = ptr[3]; if (!rows || !chans) { p->n_rows = 1; p->n_entries = 0; continue; } psize = (psize + 15) & ~15; if (offset + psize > size) goto error_fb; end = ptr + psize; ptr += 4; p->n_rows = rows; p->n_entries = rows; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { row++; continue; } if (flags & 0xE0) { p->n_entries++; if (flags & 0x80) ptr += 2; if (flags & 0x40) ptr++; if (flags & 0x20) { if (*ptr == 40) ptr += 4; else ptr += 2; } } } entry = malloc(p->n_entries * sizeof(*p->entry)); if (!entry) goto error_fb; p->entry = entry; ptr = buffer + offset + 4; row = 0; while ((row < rows) && (ptr < end)) { flags = *ptr++; if (!flags) { IT_SET_END_ROW(entry); entry++; row++; continue; } if (flags & 0xE0) { entry->mask = 0; entry->channel = channel = flags & 0x1F; if (channel >= chans) { // channel = 0; // goto error_fb; } if (flags & 0x80) { if ((*ptr < 60) && (channel < pchans)) { entry->mask |= IT_ENTRY_NOTE; entry->note = *ptr + 35; } ptr++; if (*ptr) { entry->mask |= IT_ENTRY_INSTRUMENT; entry->instrument = *ptr; } ptr++; } if (flags & 0x40) { if (*ptr <= 64) { entry->mask |= IT_ENTRY_VOLPAN; entry->volpan = *ptr; } ptr++; } if (flags & 0x20) { entry->mask |= IT_ENTRY_EFFECT; switch (*ptr) { case 1: entry->effect = IT_XM_FINE_VOLSLIDE_UP; entry->effectvalue = ptr[1]; break; case 2: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = (ptr[1] << 4) & 0xF0; break; case 3: entry->effect = IT_XM_FINE_VOLSLIDE_DOWN; entry->effectvalue = ptr[1]; break; case 4: entry->effect = IT_VOLUME_SLIDE; entry->effectvalue = ptr[1] & 0xF; break; case 10: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]); break; case 11: entry->effect = IT_PORTAMENTO_UP; entry->effectvalue = ptr[1]; break; case 12: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF); break; case 13: entry->effect = IT_PORTAMENTO_DOWN; entry->effectvalue = ptr[1]; break; case 14: entry->effect = IT_TONE_PORTAMENTO; entry->effectvalue = ptr[1]; break; case 15: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15); break; case 16: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] << 4; break; case 17: entry->effect = IT_VOLSLIDE_TONEPORTA; entry->effectvalue = ptr[1] & 0xF; break; case 20: entry->effect = IT_VIBRATO; entry->effectvalue = ptr[1]; break; case 21: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11); break; case 22: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] << 4; break; case 23: entry->effect = IT_VOLSLIDE_VIBRATO; entry->effectvalue = ptr[1] & 0xF; break; case 30: entry->effect = IT_TREMOLO; entry->effectvalue = ptr[1]; break; case 31: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE( IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11); break; case 40: entry->effect = IT_SET_SAMPLE_OFFSET; entry->effectvalue = ptr[2]; ptr += 2; break; case 41: entry->effect = IT_XM_RETRIGGER_NOTE; entry->effectvalue = ptr[1]; break; case 42: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF); break; case 43: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF); break; case 50: entry->effect = IT_JUMP_TO_ORDER; entry->effectvalue = ptr[1]; break; case 51: entry->effect = IT_BREAK_TO_ROW; entry->effectvalue = ptr[1]; break; case 52: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF); break; case 53: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF); break; case 60: entry->effect = IT_SET_SPEED; entry->effectvalue = ptr[1]; break; case 61: entry->effect = IT_SET_SONG_TEMPO; entry->effectvalue = ptr[1]; break; case 70: entry->effect = IT_ARPEGGIO; entry->effectvalue = ptr[1]; break; case 71: entry->effect = IT_S; entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF); break; case 72: /* "balance" ... panning? */ entry->effect = IT_SET_PANNING; entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7; break; default: entry->mask &= ~IT_ENTRY_EFFECT; }