#include #include "yxm.h" /* --------------------------------------------------------------------- // Function: SetYXMVolume // Purpose: Set the volume of the current used voices according // to globvol */ void SetYXMVolume(YXM_MODDATA *yxmdata) { unsigned short volL,volR,newvolL,newvolR; short i; volL = yxmdata->yxmd_globvolL; volR = yxmdata->yxmd_globvolR; for(i=0; i < yxmdata->yxmd_channels; i++) { if (yxmdata->yxmd_channel[i].voice != -1) { newvolL = (yxmdata->yxmd_channel[i].vol_l * volL); newvolR = (yxmdata->yxmd_channel[i].vol_r * volR); newvolL = newvolL >> 7; newvolR = newvolR >> 7; SsUtSetVVol(yxmdata->yxmd_channel[i].voice, newvolL, newvolR); } } } /* --------------------------------------------------------------------- // Function: StopYXM // Purpose: Stop playing tune and set Keys OFF */ unsigned short StopYXM(YXM_MODDATA *yxmdata) { SsUtAllKeyOff(0); yxmdata->yxmd_playflag = -1; return(yxmdata->yxmd_songpos); } /* --------------------------------------------------------------------- // Function: ResetYXM // Purpose: Reset Module to play from begining */ void ResetYXM(YXM_MODDATA *yxmdata, unsigned short oldpos) { short i; unsigned long *ptr; unsigned short *patptr; yxmdata->yxmd_count = 0; yxmdata->yxmd_songpos = oldpos; yxmdata->yxmd_row = 0; yxmdata->yxmd_rows = 0; yxmdata->yxmd_patternpos = 0; ptr = yxmdata->yxmd_patternOT; ptr+=oldpos; yxmdata->yxmd_patternpos = (unsigned char *) *ptr; patptr = (unsigned short *)yxmdata->yxmd_patternpos; yxmdata->yxmd_rows = *(patptr+1); patptr+=2; yxmdata->yxmd_patternpos = (unsigned char *) patptr; // ==== Clear Channel Data for (i=0; i < 15; i++) { yxmdata->yxmd_channel[i].note = 0; yxmdata->yxmd_channel[i].vag = 0; yxmdata->yxmd_channel[i].volcol = 0; yxmdata->yxmd_channel[i].effect = 0; yxmdata->yxmd_channel[i].effpar = 0; yxmdata->yxmd_channel[i].vol_l = 0; yxmdata->yxmd_channel[i].vol_r = 0; yxmdata->yxmd_channel[i].voice = -1; } yxmdata->yxmd_playflag = 0; } /* --------------------------------------------------------------------- // Function: Init_YXM // Purpose: Initialize Module ** IN: VH / VAB Header file ** VB / VAB Voice Bank ** YXM / Module Data ** YXMPLAY / Structure for player */ extern short InitYXM(unsigned char *VH, unsigned char *VB, unsigned char *YXM, YXM_MODDATA *yxmdata) { YXM_HEADER *yxmhead; unsigned long *ptr; unsigned short *patptr; short i; short ret=0; yxmhead=(YXM_HEADER *)YXM; if (!(strncmp(yxmhead->yxm_id,"YXM!",4))) { // ==== Set MODDATA yxmdata->yxmd_tempo = yxmhead->yxm_tempo; yxmdata->yxmd_songlength = yxmhead->yxm_songlength; yxmdata->yxmd_restartpos = yxmhead->yxm_restartpos; yxmdata->yxmd_channels = yxmhead->yxm_channels; yxmdata->yxmd_patternOT = &yxmhead->yxm_patternOT[0]; yxmdata->yxmd_count = 0; yxmdata->yxmd_songpos = 0; yxmdata->yxmd_row = 0; yxmdata->yxmd_rows = 0; yxmdata->yxmd_patternpos = 0; yxmdata->yxmd_globvolL = 127; yxmdata->yxmd_globvolR = 127; yxmdata->yxmd_patternloopflag = 0; // ==== Calc Real Pattern Address ptr = &yxmdata->yxmd_patternOT[0]; for (i=0; i < yxmdata->yxmd_songlength; i++, ptr++) { *ptr+=(unsigned long)yxmhead; } // ==== Set Pattern ptr = yxmdata->yxmd_patternOT; yxmdata->yxmd_patternpos = (unsigned char *) *ptr; patptr = (unsigned short *)yxmdata->yxmd_patternpos; yxmdata->yxmd_rows = *(patptr+1); patptr+=2; yxmdata->yxmd_patternpos = (unsigned char *) patptr; // ==== Set Instrument Data Pointer yxmdata->yxmd_instrumentdata = (short *)&yxmhead->yxm_instrumentinfo[0]; // ==== Clear Channel Data for (i=0; i < 15; i++) { yxmdata->yxmd_channel[i].note = 0; yxmdata->yxmd_channel[i].vag = 0; yxmdata->yxmd_channel[i].volcol = 0; yxmdata->yxmd_channel[i].effect = 0; yxmdata->yxmd_channel[i].effpar = 0; yxmdata->yxmd_channel[i].vol_l = 0; yxmdata->yxmd_channel[i].vol_r = 0; yxmdata->yxmd_channel[i].voice = -1; } // ==== Load Sample Into Sample Buffer yxmdata->yxmd_vabid = SsVabTransfer(VH, VB,-1,1); /* if(yxmdata->yxmd_vabid < 0) { printf(" vab:%d", yxmdata->yxmd_vabid); return(1); } */ SsSetMVol(yxmdata->yxmd_globvolL,yxmdata->yxmd_globvolR); } else ret=1; return(ret); } /* --------------------------------------------------------------------- // Function: RemoveYXM // Purpose: Remove the VAB from sound buffer ** YXM_MODDATA / Structure for player */ void RemoveYXM(YXM_MODDATA *yxmdata) { yxmdata->yxmd_playflag = -1; SsUtAllKeyOff(0); SsVabClose(yxmdata->yxmd_vabid); } /* --------------------------------------------------------------------- // Function: PlayYXM // Purpose: Play Module */ asm PlayYXM(YXM_MODDATA *mod) { typedef YXM_MODDATA Y; typedef YXM_PATTERN_HEADER PH; typedef YXM_CHANNEL C; typedef YXM_INSTRUMENT I; .set reorder addiu sp,sp,-68 sw ra, 28(sp) sw s0, 32(sp) sw s1, 36(sp) sw s2, 40(sp) sw s3, 44(sp) sw s4, 48(sp) sw s5, 52(sp) sw s6, 56(sp) sw s7, 60(sp) // =================================== // move s0, a0 // s0 = *mod lhu t0, Y.yxmd_playflag(s0) // get flag bne t0, $0, yxm_exit lh t0, Y.yxmd_count(s0) // yxmd_count addi t0, t0, -1 // -1 move t1, t0 // save result bgtz t0, yxm_0 // if < lh t0, Y.yxmd_tempo(s0) // get tempo yxm_0: sh t0, Y.yxmd_count(s0) // update yxmd_count bgtz t1, yxm_do_effects // if count > 0 do effects lh t0, Y.yxmd_row(s0) // row lh t1, Y.yxmd_rows(s0) // rows bne t0, t1, yxm_do_channels // if row != rows do row sh $0, Y.yxmd_row(s0) // clear row lw t0, Y.yxmd_patternOT(s0) // *patterns OT lh t1, Y.yxmd_songpos(s0) // songpos lh t2, Y.yxmd_songlength(s0) // songlength addiu t1, t1, 1 // songpos++ bne t1, t2, yxm_1 // if songpos == songlength lhu t1, Y.yxmd_restartpos(s0) // get restart pos yxm_1: sh t1, Y.yxmd_songpos(s0) // update songpos sll t1, t1, 2 // songpos * 4 addu t0, t0, t1 // get pointer in list lw t1, 0(t0) // get new pattern ptr lhu t2, PH.yxmpat_rows(t1) // get rows addiu t1, t1, sizeof(PH) // skip size/rows sh t2, Y.yxmd_rows(s0) // store rows sw t1, Y.yxmd_patternpos(s0) // store *pattern data // =================================== // Play Channels Loop yxm_do_channels: lh t0, Y.yxmd_channels(s0) // # channels sh t0, 64(sp) // store on stack lw s1, Y.yxmd_patternpos(s0) // current position in pattern addiu s2, s0, 48 // *channel0 data // ================ // PLAY CHANNELS LOOP yxm_channel_loop: lbu s3, 0(s1) // note lbu s4, 1(s1) // vag (instrument) lbu s5, 2(s1) // volume column effect lbu s6, 3(s1) // effect type lbu s7, 4(s1) // effect parameter addi s4, s4, -1 // instrument-=1; beq s3, $0, yxm_get_effects // if !note get effects lh t1, C.voice(s2) // get channel voice li at, -1 beq t1, at, yxm_play_voice // if voice != -1 stop voice // ================ // STOP VOICE lh t0, C.note(s2) // previouse note lh a3, C.vag(s2) // previouse vag move a2, $0 // prog == 0 lh a1, Y.yxmd_vabid(s0) // vabID move a0, t1 // get voice sw t0, 16(sp) // store note on stack jal SsUtKeyOff li at, -1 sh at, C.voice(s2) // signal voice is off sh $0, C.note(s2) // clear note // ================ // PLAY INSTRUMNET yxm_play_voice: li at, 97-15 // KEY OFF note beq s3, at, yxm_get_effects // if note == KEY OFF note // get effects li at, -1 bne s4, at, yxm_pv_0 // if vag == -1 lh s4, C.vag(s2) // use previouse vag yxm_pv_0: move a3, s3 // note move a2, s4 // vag move a1, $0 // program = 0 lh a0, Y.yxmd_vabid(s0) // vabid sh s3, C.note(s2) // store new note(channel data) sh s4, C.vag(s2) // store new vag(channel data) lw t0, Y.yxmd_instrumentdata(s0) // *instrument info sll t1, a2, 2 // vag * 4 addu t0, t0, t1 // offset + ptr lhu t1, I.i_finetune(t0) // get fine tune lhu t2, I.i_volume(t0) // get volume (instrument data) li at, EFF_VOLUME // test if Effect: Volume bne at, s6, yxm_pv_volcol // if effect != 0xC check // Volume Column move t2, s7 // t2 = effect parameter move s6, $0 // clear effect type move s7, $0 // clear effect paramter b yxmc2 // calculate volume yxm_pv_volcol: // check VolumeColumn if no 0xC beq s5, $0, yxmc1 // VolumnColumn == 0 & no 0xC // use instrument data volume li t3, 0x51 sltu at, s5, t3 // if >= 0x51 beq at, $0, yxmc1 // use instrument data volume addi t2, s5, -16 // - 0x10 move s5, $0 // clear VolumeColumn yxmc2: addu t2, t2, t2 // Volume * 2 beq t2, $0, yxmc1 // if == 0 KEY ON addi t2, t2, -1 // - 1 yxmc1: lhu t8, Y.yxmd_globvolL(s0) // get global volume bne t8, $0, yxmc5 // if == 0 set volume to 0 move t2, $0 b yxmc4 yxmc5: addiu t9, t2, 1 // ++ multu t8, t9 // volume * gloval nop nop mflo t9 srl t8, t9, 7 // / 128 andi t2, t8, 0x7F // result ready yxmc4: sw t1, 16(sp) // store fine tune sw t2, 20(sp) // store volume left sw t2, 24(sp) // store volume right sh t2, C.vol_l(s2) // set new volumne(ChannelData) sh t2, C.vol_r(s2) // ditto jal SsUtKeyOn sh v0, C.voice(s2) // save channel voice yxm_get_effects: sh s5, C.volcol(s2) // save VolumeColumn sh s6, C.effect(s2) // save Effect beq s7, $0, yxmc3 // if EffectParameter == 0 no store sh s7, C.effpar(s2) // save Effect Paramter yxmc3: addiu s2, s2, sizeof(C) // next ChannelData addiu s1, s1, 5 // next channel in pattern lh t0, 64(sp) addi t0, t0, -1 // counter -=1 sh t0, 64(sp) bne t0, $0, yxm_channel_loop // if != 0 LOOP sw s1, Y.yxmd_patternpos(s0) // save next row pointer lh t0, Y.yxmd_row(s0) // increase addiu t0, t0, 1 // row sh t0, Y.yxmd_row(s0) // counter // =================================== // Analyse Effects yxm_do_effects: // s0 = *mod addiu s1, s0, 48 // s1 = *ChannelData lh s2, Y.yxmd_channels(s0) // s2 = Counter li s3, -1 // s3 = -1 // ================ // Check Effects Loop yxm_de_loop: lh s4, C.voice(s1) // s4 = Channel Voice lh t1, C.volcol(s1) // t1 = Volume Column Effect // if voice == -1 next channel beq s4, s3, yxm_do_next_channel_effect // =============== // Compare Volume Column Effects beq t1, $0, yxm_EFFECTS // if == 0 effect li t2, 0x51 // sltu at, t1, t2 // beq at, $0, yxm_EFFECTS // if < 0x51 set volume addi t0, t1, -16 // - 16 addu t0, t0, t0 // Volume * 2 beq t0, $0, yxm_volcol_0 // if != 0 addi t0, t0, -1 // volume -- yxm_volcol_0: sh t0, C.vol_l(s1) // save volume sh t0, C.vol_r(s1) // ditto move a0, s4 // voice move a1, t0 // volume l move a2, t0 // volume r jal SsUtSetVVol // set it sh $0, C.volcol(s1) // clear VolumeColumn Effect // =============== // Compare Effects yxm_EFFECTS: lh t0, C.effect(s1) // get effect // if effect == 0 next channel beq t0, $0, yxm_do_next_channel_effect li at, EFF_KEY_OFF // EFFECTS beq t0, at, yxm_effect_KEY_OFF li at, EFF_VOLUME beq t0, at, yxm_effect_VOLUME li at, EFF_PATBREAK beq t0, at, yxm_effect_PATTERN_BREAK li at, EFF_TEMPO beq t0, at, yxm_effect_TEMPO li at, EFF_GLOBAL_VOLUME beq t0, at, yxm_effect_GLOBAL_VOLUME li at, EFF_E_EFFECT beq t0, at, yxm_effect_E b yxm_do_next_channel_effect // =============== // EFFECT: KEY OFF yxm_effect_KEY_OFF: lh t0, C.note(s1) // note lh a3, C.vag(s1) // vag move a2, $0 // prog lh a1, Y.yxmd_vabid(s0) // vabID move a0, s4 // voice sw t0, 16(sp) // note jal SsUtKeyOff li at, -1 sh at, C.voice(s1) // signal vox is off sh $0, C.effect(s1) // clear effect sh $0, C.effpar(s1) // ditto for parameter b yxm_do_next_channel_effect // =============== // EFFECT: VOLUME yxm_effect_VOLUME: lhu t0, C.effpar(s1) // get volume addu t0, t0, t0 // volume *2 beq t0, $0, yxm_effvol_0 // if != 0 addi t0, t0, -1 // -- yxm_effvol_0: sh t0, C.vol_l(s1) // save volume l sh t0, C.vol_r(s1) // save volume r move a0, s4 // voice move a1, t0 // volume l move a2, t0 // volume r jal SsUtSetVVol sh $0, C.effect(s1) // clear effect sh $0, C.effpar(s1) b yxm_do_next_channel_effect // =============== // EFFECT: PATTERN BREAK yxm_effect_PATTERN_BREAK: lhu t0, C.effpar(s1) // get positon lhu t1, Y.yxmd_songpos(s0) // lhu t2, Y.yxmd_songlength(s0) // addiu t1, t1, 1 // increase song pos bne t1, t2, yxm_eff_PB // if end of song lhu t1, Y.yxmd_restartpos(s0) // get restart pos yxm_eff_PB: sh t1, Y.yxmd_songpos(s0) // update songpos lw t2, Y.yxmd_patternOT(s0) // get pattern addresses sll t1, t1, 2 // songpos * 4 addu t2, t2, t1 // get pointer in list lw t3, 0(t2) // get new pattern ptr lhu t4, PH.yxmpat_rows(t3) // get rows addiu t3, t3, sizeof(PH) // skip size/rows beq t0, $0, yxm_eff_PB_1 // row number != 0 lhu at, Y.yxmd_channels(s0) // calculate position multu t0, at // row * # channels move t4, t0 // t4 = rows nop mflo t5 // t5 = result sll t6, t5, 2 // *4 addu t6, t6, t5 // +1 addu t3, t3, t6 // t3 = *pattern data yxm_eff_PB_1: sh t4, Y.yxmd_rows(s0) // store rows sw t3, Y.yxmd_patternpos(s0) // store *pattern data sh $0, C.effect(s1) sh $0, C.effpar(s1) b yxm_do_next_channel_effect // =============== // EFFECT: TEMPO yxm_effect_TEMPO: lhu t0, C.effpar(s1) // get tempo bne t0, $0, yxm_eff_T // if == 0 li t0, 1 // set to 1 yxm_eff_T: sh t0, Y.yxmd_tempo(s0) // set new tempo sh t0, Y.yxmd_count(s0) sh $0, C.effect(s1) sh $0, C.effpar(s1) b yxm_do_next_channel_effect // =============== // EFFECT: GLOBAL VOLUME yxm_effect_GLOBAL_VOLUME: lhu t0, C.effpar(s1) // get volume addu t0, t0, t0 beq t0, $0, yxm_eff_GV addi t0, t0, -1 yxm_eff_GV: sh t0, Y.yxmd_globvolL(s0) // save global volume l sh t0, Y.yxmd_globvolR(s0) // save global volume r sh $0, C.effect(s1) sh $0, C.effpar(s1) // // move a0, t0 // move a1, t0 // jal SsSetMVol b yxm_do_next_channel_effect // =============== // EFFECT: E - EFFECTS yxm_effect_E: lhu t0, C.effpar(s1) andi t1, t0, 0xF // t1 = 0x0y andi t0, t0, 0xF0 li at, EFF_E_PATLOOP beq at, t0, yxm_eeff_PATTERN_LOOP b yxm_do_next_channel_effect // =============== // E-EFFECT: PATTERN LOOP yxm_eeff_PATTERN_LOOP: bne t1, $0, yxm_eeff_PL_0 // if t1!=0 set pos lh at, Y.yxmd_patternloopflag(s0) // check if flag set bne at, $0, yxm_do_next_channel_effect // avoid resetting when // when looping lhu t0, Y.yxmd_channels(s0) // # channels li at, 5 // BYTES PER CHANNEL multu at, t0 lw t2, Y.yxmd_patternpos(s0) // get pattern pos nop mflo t0 subu t1, t2, t0 // get previouse row sw t1, Y.yxmd_patternlooppos(s0) // save pointer li at, -1 // sh at, Y.yxmd_patternloopflag(s0) // signal pattern move t1, $0 b yxm_eeff_PL_1 // loop begin set yxm_eeff_PL_0: lh t0, Y.yxmd_patternloopflag(s0) // test flag beq t0, $0, yxm_eeff_PL_1 // if == 0 no begin set move t1, $0 // count == 0 yxm_eeff_PL_1: sh t1, Y.yxmd_patternloopcount(s0) // set count sh $0, C.effect(s1) sh $0, C.effpar(s1) // b yxm_do_next_channel_effect // nop // nop // nop yxm_do_next_channel_effect: addiu s1, s1, sizeof(C) addi s2, s2, -1 bne s2, $0, yxm_de_loop yxm_exit: lw ra, 28(sp) lw s0, 32(sp) lw s1, 36(sp) lw s2, 40(sp) lw s3, 44(sp) lw s4, 48(sp) lw s5, 52(sp) lw s6, 56(sp) lw s7, 60(sp) addi sp, sp, 68 jr ra }