#include /**/ #include "defs.h" /*->inst.h (u8,u16x,...)*/ #include "inst.h" /*SampleInfo*/ #include "playnote.h" /*Note*/ #include "hirev.h" /*(instHirevXX)*/ #include "dacio.h" /*(dacioGlobalVol)*/ static SampleInfo *smp; static void commonWork(const Note *np) { instClearPFW(); if (np->ins) instSample(&smp[np->ins - 1], 0); if (np->note != 255) if (np->note == 254) instNoteOff(0); else instNote((np->note/16) * 12 + np->note%16, 0); if (np->vol != 255) instVol(np->vol, 0); } static void noEffect(const Note *np) { if (np->cmd == 255) instEmptyCmd(); commonWork(np); } static void unknownEffect(const Note *np) { fprintf(stderr, "Unknown effect: %c%02X \n", np->cmd + '@', np->info); commonWork(np); } #define X (np->info/16) #define Y (np->info%16) /* Dxy, Kxy, Lxy common work */ static void dklCommonWork(const Note *np) { if (np->info) { if (Y == 0) /* Dx0=up */ instSetVolSlideParams(X, 1, 1, 1, 0); else if (X > 0 && Y == 0xf) /* DxF=fine up */ instSetVolSlideParams(X, 1, 1, 1, 1); else if (X == 0xf) /* DFy=fine down */ instSetVolSlideParams(-Y, 1, 1, 1, 1); else /* D0y=down, but also D46 or something is here */ instSetVolSlideParams(-Y, 1, 1, 1, 0); } instVolSlide(); } /* Dxy = volume slide */ static void dCmd(const Note *np) { commonWork(np); dklCommonWork(np); } /* Exx, Fxx common work */ static void efCommonWork(const Note *np) { if (np->info) { switch (X) { case 0xf: /* [EF]Fx = fine */ instSetPeriodSlideParams((np->info%16)*4, 1); break; case 0xe: /* [EF]Ex = extra fine */ /* ST3 plays [EF]E0 and [EF]F0 differently */ /* so it may be incompatible.. */ instSetPeriodSlideParams(np->info%16, 1); break; default: instSetPeriodSlideParams(np->info*4, 0); } } } /* Exx = slide down */ static void eCmd(const Note *np) { commonWork(np); efCommonWork(np); instPeriodSlideDown(); } /* Fxx = slide up */ static void fCmd(const Note *np) { commonWork(np); efCommonWork(np); instPeriodSlideUp(); } /* Gxx = portamento */ static void gCmd(const Note *np) { instClearPFW(); if (np->ins) instSetPortamentoDefaultVol(); /* only set default volume */ if (np->vol != 255) instVol(np->vol, 0); if (np->note < 254 ) instSetPortamentoTo((np->note/16)*12 + np->note%16); if (np->info) instSetPortamentoSpeed(np->info*4); instPortamento(); } /* Hxy = vibrato */ static void hCmd(const Note *np) { commonWork(np); if (np->info) instSetVibratoParams(X, Y*8); instVibrato(); } /* Ixy = tremor */ static void iCmd(const Note *np) { commonWork(np); if (np->info) instSetTremorParams(X+1, Y+1); instTremor(); } /* Jxy = arpeggio */ static void jCmd(const Note *np) { commonWork(np); if (np->info) instSetArpeggioParams(X, Y); #if 0 instSetArpeggioParams(note[np->note/16][np->note%16 + X], note[np->note/16][np->note%16 + Y]); #endif instArpeggio(); } /* Kxy = H00 and Dxy */ static void kCmd(const Note *np) { commonWork(np); instVibrato(); /* H00 */ dklCommonWork(np); } /* Lxy = G00 and Dxy */ static void lCmd(const Note *np) { commonWork(np); instPortamento(); /* G00 */ dklCommonWork(np); } /* Oxx = sample offset */ static void oCmd(const Note *np) { commonWork(np); instSampleOffset(np->info * 0x100); } /* Qxy = retrig + volumeslide */ static void qCmd(const Note *np) { static i15x add[16]={0,-1,-2,-4,-8,-16,0,0,0,1,2,4,8,16,0,0}; static i15x mul[16]={1,1,1,1,1,1,2,1,1,1,1,1,1,1,3,2}; static i15x div[16]={1,1,1,1,1,1,3,2,1,1,1,1,1,1,2,1}; commonWork(np); if (np->info) { instSetVolSlideParams(add[X], mul[X], div[X], Y, 0); instSetRetrigParam(Y); } instVolSlide(); instRetrig(); } /* Rxy = tremolo */ static void rCmd(const Note *np) { commonWork(np); if (np->info) instSetTremoloParams(X, Y*2); instTremolo(); } /* Uxy = fine vibrato */ static void uCmd(const Note *np) { commonWork(np); if (np->info) instSetVibratoParams(X, Y*2); instVibrato(); } /* Sxy = misc */ static void sCmd(const Note *np) { if (X == 0xd) { /* notedelay */ instClearPFW(); if (np->ins) instSample(&smp[np->ins - 1], Y); if (np->note != 255) if (np->note == 254) instNoteOff(Y); else instNote((np->note/16) * 12 + np->note%16, Y); if (np->vol != 255) instVol(np->vol, Y); } else { commonWork(np); switch (X) { #if 0 /* merged with "default:" */ case 0: /* set filter */ fprintf(stderr, "Warning: set filter\n"); break; #endif case 1: /* set glissando control */ instSetPortamentoGlissando(Y); break; case 2: /* set finetune */ /* ...but not tested yet. which tune use this? */ printf("Got it! Set Finetune\n"); { static i15x freq[16] = { 8363,8413,8463,8529,8581,8651,8723,8757, 7895,7941,7985,8046,8107,8169,8232,8280 }; instTuning(freq[Y]); /* the tuning effects from next key-on */ } break; case 3: /* set vibrato waveform */ instSetVibratoWave(Y%4, Y/4); break; case 4: /* set tremolo waveform */ instSetTremoloWave(Y%4, Y/4); break; case 8: /* set pan position */ instPanPosition(Y*64/15); break; case 0xc: /* notecut */ instNoteCut(Y); break; case 0xb: /* pattern loop */ case 0xe: /* pattern delay */ break; default: fprintf(stderr, "Warning: %c%02X not supported.\n", np->cmd+'@', np->info); } } } /* Vxx = set global volume */ static i15x masterVol = 0x30 * 4/3; static i15x globalVol = 0x40; static void setGlobalVol(void) { dacioGlobalVol(masterVol * globalVol); } static i15x mono; void playNoteSetMono(i15x m) { mono = m; instMono(m); } void playNoteSetMasterVol(i15x mv) { masterVol = mono? mv : mv * 4 / 3; setGlobalVol(); } void playNoteSetGlobalVol(i15x gv) { globalVol = gv; setGlobalVol(); } static void vCmd(const Note *np) { commonWork(np); playNoteSetGlobalVol(np->info); } /* Xxx = DMP style pan position */ static void xCmd(const Note *np) { commonWork(np); if (np->info <= 0x80) instPanPosition(np->info * 64 / 0x80); else if (np->info == 0xa4) instPanPosition(-1); /* surround */ else instPanPosition(32); /* unknown -> center */ } /* Z0x = pan position (crawling.s3m) */ #ifdef ZCMD_PAN static void zCmd(const Note *np) { commonWork(np); instPanPosition(np->info*64/15); } #endif static void (*cmdTbl[])(const Note *np) = { /*@*/unknownEffect, /*A*/noEffect, /*B*/noEffect, /*C*/noEffect, /*D*/dCmd, /*E*/eCmd, /*F*/fCmd, /*G*/gCmd, /*H*/hCmd, /*I*/iCmd, /*J*/jCmd, /*K*/kCmd, /*L*/lCmd, /*M*/unknownEffect, /*N*/unknownEffect, /*O*/oCmd, /*P*/unknownEffect, /*Q*/qCmd, /*R*/rCmd, /*S*/sCmd, /*T*/noEffect, /*U*/uCmd, /*V*/vCmd, /* ??? */ /*W*/unknownEffect, /*X*/xCmd, /*Y*/unknownEffect, #ifdef ZCMD_PAN /*Z*/zCmd #else /*Z*/unknownEffect #endif }; void playNoteSetSample(SampleInfo *sip) { smp = sip; } static i31x outRate = DEF_OUTRATE; static i15x tempo = DEF_TEMPO; /* BPM = rows/minute/4 */ static i15x speed = DEF_SPEED; /* frames/row */ static i15x frameLen = DEF_OUTRATE*60/(DEF_TEMPO*24); void playNoteInit(void) { instInit(); /*instOutRate(OUTRATE);*/ /*instFrameLen(frameLen);*/ /*initNoteTable();*/ } static void setFrameLen(void) { frameLen = outRate * 60 / (tempo * 24); /*instFrameLen(frameLen);*/ instHirevSetFrameLen(frameLen); } void playNoteSetOutRate(i31x or) { if (or > MAX_OUTRATE) { fprintf(stderr, "Too high output sample rate.\n"); exit(1); } instOutRate(or); outRate = or; setFrameLen(); } void playNoteSetTempo(i15x n) { /*printf("tempo = %d\n", n);*/ if (n < MIN_TEMPO) { fprintf(stderr, "Illegal tempo (%d) ignored.\n", n); return; } tempo = n; setFrameLen(); } void playNoteSetSpeed(i15x n) { /*printf("speed = %d\n", n);*/ speed = n; } static u8 chToPlay[32]; void playNoteSetNote(i15x ch, const Note *np) { chToPlay[ch] = 1; instSelectCh(ch); if (np->cmd == 255) noEffect(np); else (*cmdTbl[np->cmd])(np); } #if 0 static u8 channel[32]; void playNoteSetChannel(i15x ch, i15x pan) { channel[ch] = pan; } #endif static i15x patRepeat; void playNoteSetPatRepeat(i15x n) { patRepeat = n; } void playNote(void) { i15x ch; i15x f,r; for (r = 0; r <= patRepeat; r++) { for (f = 0; f < speed; f++) { instHirevEraseBuf(); for (ch = 0; ch < 32; ch++) { if (chToPlay[ch]) { instSelectCh(ch); instDoPerFrameWorks(f); /*if (!instIsNoteOff())*/ instLoop(); } } instHirevFlushBuf(); } } patRepeat = 0; for (ch = 0; ch < 32; ch++) chToPlay[ch] = 0; }