/* Player.c ----- by Teijo Kinnunen (1989) */ /* This is a code for MED song player. You can freely use it in both commercial and non-commercial programs. Tässä on MED-soittajan lähdekoodi. Sitä saa vapaasti käyttää sekä kaupallisissa, että ei-kaupallisissa ohjelmissa. */ #include #include #include #include #include #include #include #include #include "med.h" #ifdef LATTICE #include #endif extern struct CIA far ciaa; /* Remove 'far' if your compiler doesn't support it. --- Poista 'far' jos kääntäjäsi ei tunne sitä. */ static void SWareIntr(); UWORD soittorivi,soittolohko,soittolohkonnum,soittotila; struct Task *player; extern struct CLohko lohko[]; UBYTE playerlopettanut = FALSE; UBYTE varattava[] = { 0x01,0x02,0x04,0x08 }; UBYTE laiteavattu[] = { FALSE, FALSE, FALSE, FALSE }; extern UBYTE *samples[]; extern struct Kappale song; extern ULONG soittimenpituus[]; ULONG seurnuotsignmsk,askelm; UWORD periodit[] = { 856,808,762,720,678,640,604,570,538,508,480,453, 428,404,381,360,339,320,302,285,269,254,240,226, 214,202,190,180,170,160,151,143,135,127,120,113, 107,101,95, 90, 85, 80, 75, 72, 68, 64, 60, 57 }; struct IOAudio *audioioreq[4],audiopervolreq[4],audiostopreq[4],audiorepreq[4]; struct Aloitusviesti aloitusviesti; struct Soittokasky kasky; struct MsgPort *audioport[4],*playerport=NULL,*plreply; static void SoitaNuotti(kanava,taajuus,voimakkuus,soitinid) UBYTE kanava; UWORD taajuus,voimakkuus,soitinid; { register struct IOAudio *audioreq = audioioreq[kanava]; register struct IOAudio *repreq = &audiorepreq[kanava]; BeginIO((struct IORequest *)&audiostopreq[kanava]); while(GetMsg(audioport[kanava])); audioreq->ioa_Data = samples[soitinid]; if(song.stoisto[soitinid]) audioreq->ioa_Length = song.stoisto[soitinid]; else audioreq->ioa_Length = soittimenpituus[soitinid]; audioreq->ioa_Request.io_Flags = ADIOF_PERVOL; audioreq->ioa_Period = taajuus; audioreq->ioa_Volume = voimakkuus; BeginIO((struct IORequest *)audioreq); if(song.stoisto[soitinid]) { /* toistetaan ikuisesti */ repreq->ioa_Data = (UBYTE *)(samples[soitinid] + song.stoisto[soitinid]); repreq->ioa_Length = song.stoistonpit[soitinid]; BeginIO((struct IORequest *)repreq); } } void MEDPlayer() { struct Soittokasky *tamakasky; ULONG data,signmsk,plrprtmsk,odotusmsk; long snsn = AllocSignal(-1); /* seuraavan nuotin signaalin numero */ register UWORD counter = 0,period,textra; register UBYTE raitano; UBYTE argumentti[4],efekti[4],kaskynaani; UWORD edellinensoitin[4] = { 0,0,0,0 }; WORD edellinenvoim[4] = { 0,0,0,0 }; UWORD komento,edarpgpernum,laskuri,kaskynsoitin; UWORD edellinenperiod[4] = { 0,0,0,0 }; BOOL vaihdalohkoa = FALSE,ylsoitin,eikaynnisty = FALSE; BYTE ioerror; geta4(); soittotila = ALASOITA; aloitusviesti.viesti_msg.mn_ReplyPort = NULL; aloitusviesti.viesti_msg.mn_Node.ln_Type = NT_MESSAGE; aloitusviesti.viesti_msg.mn_Length = sizeof(struct Aloitusviesti); for(laskuri = 0; laskuri < 4; laskuri++) { if(!(audioport[laskuri] = CreatePort(0,0))) { eikaynnisty = TRUE; break; } if(!(audioioreq[laskuri] = (struct IOAudio *)CreateExtIO(audioport[laskuri], sizeof(struct IOAudio)))) { eikaynnisty = TRUE; break; } audioioreq[laskuri]->ioa_Request.io_Message.mn_Node.ln_Pri = 50; audioioreq[laskuri]->ioa_Data = &varattava[laskuri]; audioioreq[laskuri]->ioa_Length = 1; ioerror = OpenDevice(AUDIONAME,0,(struct IORequest *)audioioreq[laskuri],0); if(ioerror) { eikaynnisty = TRUE; break; } laiteavattu[laskuri] = TRUE; memcpy((char *)&audiopervolreq[laskuri],(char *)audioioreq[laskuri], sizeof(struct IOAudio)); memcpy((char *)&audiostopreq[laskuri],(char *)audioioreq[laskuri], sizeof(struct IOAudio)); memcpy((char *)&audiorepreq[laskuri],(char *)audioioreq[laskuri], sizeof(struct IOAudio)); audiopervolreq[laskuri].ioa_Request.io_Command = ADCMD_PERVOL; audiostopreq[laskuri].ioa_Request.io_Command = CMD_FLUSH; audioioreq[laskuri]->ioa_Request.io_Command = CMD_WRITE; audiorepreq[laskuri].ioa_Request.io_Command = CMD_WRITE; audioioreq[laskuri]->ioa_Cycles = 1; audiorepreq[laskuri].ioa_Cycles = 0; audiostopreq[laskuri].ioa_Request.io_Flags = IOF_QUICK; audiopervolreq[laskuri].ioa_Request.io_Flags = IOF_QUICK; } if(eikaynnisty || snsn == -1 || !(playerport = CreatePort(0,0))) { aloitusviesti.viesti_tilanne = PIELEENMENI; PutMsg(plreply,(struct Message *)&aloitusviesti); goto playerinloppu; } seurnuotsignmsk = 1 << snsn; plrprtmsk = 1 << playerport->mp_SigBit; odotusmsk = seurnuotsignmsk | plrprtmsk; /* säästää aikaa laskea se nyt */ aloitusviesti.viesti_tilanne = KAIKKIHYVIN; PutMsg(plreply,(struct Message *)&aloitusviesti); for(;;) { signmsk = Wait(odotusmsk); if(signmsk & plrprtmsk) { tamakasky = (struct Soittokasky *)GetMsg(playerport); komento = tamakasky->kasky_komento; data = tamakasky->kasky_data; kaskynaani = tamakasky->kasky_aani; kaskynsoitin = tamakasky->kasky_soitin; ReplyMsg((struct Message *)tamakasky); if(komento == OHJELMANLOPPU) break; if(komento == SOITALOHKO) { soittotila = SOITALOHKOA; soittolohko = data; } else if(komento == SOITAKAPPALE) { soittotila = SOITAKAPPALETTA; soittolohkonnum = data; soittolohko = song.soittojarjestys[soittolohkonnum]; } else if(komento == SOITANUOTTI) SoitaNuotti(kaskynaani,(UWORD)data, (UWORD)song.soittimenvoimakkuus[kaskynsoitin],kaskynsoitin); else if(komento == SEIS) soittotila = ALASOITA; } if(signmsk & seurnuotsignmsk) { if(soittotila == ALASOITA) continue; if(++counter == 6) { counter = 0; for(raitano = 0; raitano < 4; raitano++) { period=lohko[soittolohko].pala[soittorivi].savel[raitano].savel_period; textra=lohko[soittolohko].pala[soittorivi].savel[raitano].savel_extra; argumentti[raitano] = (textra & 0x00ff); if(period & 0x8000) { /* jos periodin ylin bitti asetettu */ period &= ~0x8000; /* otetaan se pois */ ylsoitin = TRUE; } else ylsoitin = FALSE; if(textra & 0xf000 || ylsoitin) { edellinensoitin[raitano]=((textra&0xf000)>>12)+(ylsoitin?16:0); edellinenvoim[raitano] = song.soittimenvoimakkuus[edellinensoitin[raitano]]; } if(efekti[raitano] = ((textra & 0x0f00) >> 8)) { if(efekti[raitano] == 0x0f) { if(argumentti[raitano]) askelm = 625000 / argumentti[raitano]; else vaihdalohkoa = TRUE; } else if(efekti[raitano] == 0x0c) edellinenvoim[raitano] = /* vvv-kerrotaan kymmenellä */ ((argumentti[raitano]>>1)&0xf8)+((argumentti[raitano]>>3)&0xfe)+ (argumentti[raitano] & 0x0f); } if(period) { edellinenperiod[raitano] = period; SoitaNuotti(raitano,period,edellinenvoim[raitano], edellinensoitin[raitano]); } } if(++soittorivi > 63 || vaihdalohkoa) { if(soittotila == SOITALOHKOA) soittorivi = 0; else if(soittotila == SOITAKAPPALETTA) { soittorivi = 0; if(++soittolohkonnum > song.kappaleen_pituus-1) soittolohkonnum = 0; if((soittolohko = song.soittojarjestys[soittolohkonnum]) > song.lohkoja - 1) soittolohko = song.lohkoja - 1; } vaihdalohkoa = FALSE; } } for(raitano = 0; raitano < 4; raitano++) { period = 0; switch(efekti[raitano]) { case 0x01: /* liukuu ylös.. */ if(song.vaihtoja == 5 && !counter) break; edellinenperiod[raitano] -= argumentti[raitano]; if(edellinenperiod[raitano] < 113) edellinenperiod[raitano] = 113; break; case 0x02: /* sama alas */ if(song.vaihtoja == 5 && !counter) break; edellinenperiod[raitano] += argumentti[raitano]; if(edellinenperiod[raitano] > 856) edellinenperiod[raitano] = 856; break; case 0x03: /* vibrato */ if(counter < 3) period = edellinenperiod[raitano] - argumentti[raitano]; else period = edellinenperiod[raitano]; break; case 0x0d: case 0x0e: /* voimakkuuden muutos */ if(argumentti[raitano] >> 4 == 0) { /* hiljennä */ if((edellinenvoim[raitano] -= argumentti[raitano]) < 0) edellinenvoim[raitano] = 0; } else { /* suurenna */ if((edellinenvoim[raitano] += (argumentti[raitano] >> 4)) > 64) edellinenvoim[raitano] = 64; } break; case 0x00: /* arpeggio */ if(!argumentti[raitano]) continue; switch(counter) { case 0: for(edarpgpernum = 0; edarpgpernum < 36; edarpgpernum++) if(edellinenperiod[raitano] >= periodit[edarpgpernum]) break; case 3: period = periodit[edarpgpernum + (argumentti[raitano] & 0x0f)]; break; case 1: case 4: period = periodit[edarpgpernum + (argumentti[raitano] >> 4)]; break; default: /* 2 ja 5 */ period = edellinenperiod[raitano]; break; } break; case 0x0c: break; default: continue; } if(period) audiopervolreq[raitano].ioa_Period = period; else audiopervolreq[raitano].ioa_Period = edellinenperiod[raitano]; audiopervolreq[raitano].ioa_Volume = edellinenvoim[raitano]; BeginIO((struct IORequest *)&audiopervolreq[raitano]); } } } playerinloppu: for(laskuri = 0; laskuri < 4; laskuri++) { if(laiteavattu[laskuri]) { if(!CheckIO((struct IORequest *)audioioreq[laskuri])) AbortIO((struct IORequest *)audioioreq[laskuri]); audioioreq[laskuri]->ioa_Request.io_Command = CMD_RESET; DoIO((struct IORequest *)audioioreq[laskuri]); CloseDevice((struct IORequest *)audioioreq[laskuri]); } if(audioioreq[laskuri]) DeleteExtIO((struct IORequest *)audioioreq[laskuri]); if(audioport[laskuri]) DeletePort(audioport[laskuri]); } if(playerport) DeletePort(playerport); if(snsn != -1) FreeSignal(snsn); playerlopettanut = TRUE; } struct timerequest *timereq; BOOL timerauki = FALSE; struct Interrupt sware = { { NULL,NULL,0,32,"MEDSWInt" },NULL,SWareIntr }; struct MsgPort timerport = { { NULL,NULL,NT_MSGPORT,0,NULL },PA_SOFTINT,0, (struct Task *)&sware,{ 0 } }; void SWareIntr() { geta4(); Signal(player,seurnuotsignmsk); (void)GetMsg(&timerport); timereq->tr_time.tv_micro = askelm; timereq->tr_time.tv_secs = 0L; SendIO((struct IORequest *)timereq); } LONG PLRInit() /* returns -1 if error, 0 if ok */ { struct Aloitusviesti *alkuviesti; askelm = 625000 / song.tempo; if(!(plreply = CreatePort(0,0))) return(-1); kasky.kasky_msg.mn_Node.ln_Type = NT_MESSAGE; kasky.kasky_msg.mn_ReplyPort = plreply; kasky.kasky_msg.mn_Length = sizeof(struct Soittokasky); if(!(player = CreateTask("MEDPlayer.task",21,(APTR)MEDPlayer,5000))) return(-1); WaitPort(plreply); alkuviesti = (struct Aloitusviesti *)GetMsg(plreply); if(alkuviesti->viesti_tilanne == PIELEENMENI) return(-1); NewList(&(timerport.mp_MsgList)); if(!(timereq = (struct timerequest *)CreateExtIO(&timerport, sizeof(struct timerequest)))) return(-1); if(OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *)timereq,0)) return(-1); timerauki = TRUE; timereq->tr_node.io_Command = TR_ADDREQUEST; Cause(&sware); if(song.liput & LIPPU_SUODATINPAALLA) ciaa.ciapra &= ~CIAF_LED; else ciaa.ciapra |= CIAF_LED; return(0); } void PLRPlaySong() { kasky.kasky_komento = SOITAKAPPALE; kasky.kasky_data = 0; PutMsg(playerport,(struct Message *)&kasky); WaitPort(plreply); (void)GetMsg(plreply); } void PLRStop() { kasky.kasky_komento = SEIS; PutMsg(playerport,(struct Message *)&kasky); WaitPort(plreply); (void)GetMsg(plreply); } void PLRRemove() { timerport.mp_Flags = PA_IGNORE; if(!CheckIO((struct IORequest *)timereq)) AbortIO((struct IORequest *)timereq); if(timerauki) CloseDevice((struct IORequest *)timereq); if(timereq) DeleteExtIO((struct IORequest *)timereq); ciaa.ciapra &= ~CIAF_LED; if(playerport) { kasky.kasky_komento = OHJELMANLOPPU; PutMsg(playerport,(struct Message *)&kasky); WaitPort(plreply); (void)GetMsg(plreply); while(!playerlopettanut); } if(plreply) DeletePort(plreply); }