private void partInit() { foreach (clsChip chip in chips) { chip.use = false; chip.lstPartWork = new List<partWork>(); for (int i = 0; i < chip.ChMax; i++) { partWork pw = new partWork(); pw.chip = chip; pw.isSecondary = (chip.ChipID == 1); pw.ch = i;// + 1; if (partData.ContainsKey(chip.Ch[i].Name)) { pw.pData = partData[chip.Ch[i].Name]; } pw.aData = aliesData; pw.setPos(0); pw.Type = chip.Ch[i].Type; pw.slots = 0; pw.volume = 32767; if (chip is YM2612) { pw.slots = (byte)(((pw.Type == enmChannelType.FMOPN || pw.Type == enmChannelType.FMPCM) || i == 2) ? 0xf : 0x0); pw.volume = 127; pw.MaxVolume = 127; pw.port0 = (byte)(0x2 | (pw.isSecondary ? 0xa0 : 0x50)); pw.port1 = (byte)(0x3 | (pw.isSecondary ? 0xa0 : 0x50)); } else if (chip is SN76489) { pw.MaxVolume = 15; pw.volume = pw.MaxVolume; pw.port0 = 0x50; } else if (chip is RF5C164) { pw.MaxVolume = 255; pw.volume = pw.MaxVolume; pw.port0 = 0xb1; } else if (chip is YM2610B) { pw.slots = (byte)((pw.Type == enmChannelType.FMOPN || i == 2) ? 0xf : 0x0); pw.volume = 127; pw.MaxVolume = 127; if (pw.Type == enmChannelType.SSG) { //pw.volume = 32767; pw.MaxVolume = 15; pw.volume = pw.MaxVolume; } else if (pw.Type == enmChannelType.ADPCMA) { //pw.volume = 32767; pw.MaxVolume = 31;//5bit pw.volume = pw.MaxVolume; } else if (pw.Type == enmChannelType.ADPCMB) { //pw.volume = 32767; pw.MaxVolume = 255; pw.volume = pw.MaxVolume; } pw.port0 = (byte)(0x8 | (pw.isSecondary ? 0xa0 : 0x50)); pw.port1 = (byte)(0x9 | (pw.isSecondary ? 0xa0 : 0x50)); } pw.PartName = chip.Ch[i].Name; pw.waitKeyOnCounter = -1; pw.waitCounter = 0; pw.freq = -1; pw.dataEnd = false; if (pw.pData == null || pw.pData.Count < 1) { pw.dataEnd = true; } else { chip.use = true; } chip.lstPartWork.Add(pw); } } }
private static void procBend(partWork pw) { //bend処理 if (pw.bendWaitCounter == 0) { if (pw.bendList.Count > 0) { Tuple<int, int> bp = pw.bendList.Pop(); pw.bendFnum = bp.Item1; pw.bendWaitCounter = bp.Item2; } else { pw.bendWaitCounter = -1; } } }
private void cmdDetune(partWork pw) { int n; pw.incPos(); if (!pw.getNum(out n)) { msgBox.setErrMsg("不正なディチューン'D'が指定されています。", lineNumber); n = 0; } n = checkRange(n, -127, 127); pw.detune = n; }
private void setSsgFNum(partWork pw) { int f = getSsgFNum(pw.octaveNow, pw.noteCmd, pw.shift + pw.keyShift);// if (pw.bendWaitCounter != -1) { f = pw.bendFnum; } f = f + pw.detune; for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Vibrato) { continue; } f += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } f = checkRange(f, 0, 0xfff); if (pw.freq == f) return; pw.freq = f; byte data = 0; data = (byte)(f & 0xff); outFmAdrPort(pw.port0, (byte)(0 + (pw.ch - 9) * 2), data); data = (byte)((f & 0xf00) >> 8); outFmAdrPort(pw.port0, (byte)(1 + (pw.ch - 9) * 2), data); }
private void setYM2610BADPCMAAddress(partWork pw, int startAdr, int endAdr) { if (pw.pcmStartAddress != startAdr) { outFmAdrPort(pw.port1, (byte)(0x10 + (pw.ch - 12)), (byte)((startAdr >> 8) & 0xff)); outFmAdrPort(pw.port1, (byte)(0x18 + (pw.ch - 12)), (byte)((startAdr >> 16) & 0xff)); pw.pcmStartAddress = startAdr; } if (pw.pcmEndAddress != endAdr) { outFmAdrPort(pw.port1, (byte)(0x20 + (pw.ch - 12)), (byte)(((endAdr - 0x100) >> 8) & 0xff)); outFmAdrPort(pw.port1, (byte)(0x28 + (pw.ch - 12)), (byte)(((endAdr - 0x100) >> 16) & 0xff)); pw.pcmEndAddress = endAdr; } }
private void setRf5c164LoopAddress(partWork pw, int adr) { if (pw.pcmLoopAddress != adr) { byte data = (byte)((adr >> 8) & 0xff); outRf5c164Port(pw.isSecondary, 0x5, data); data = (byte)(adr & 0xff); outRf5c164Port(pw.isSecondary, 0x4, data); pw.pcmLoopAddress = adr; } }
private void setRf5c164SampleStartAddress(partWork pw, int adr) { if (pw.pcmStartAddress != adr) { byte data = (byte)((adr >> 8) & 0xff); outRf5c164Port(pw.isSecondary, 0x6, data); pw.pcmStartAddress = adr; } }
private void setEnvelopeAtKeyOn(partWork pw) { if (!pw.envelopeMode) { pw.envVolume = 0; pw.envIndex = -1; return; } pw.envIndex = 0; pw.envCounter = 0; int maxValue = pw.MaxVolume;// (pw.envelope[8] == (int)enmChipType.RF5C164) ? 255 : 15; while (pw.envCounter == 0 && pw.envIndex != -1) { switch (pw.envIndex) { case 0: // AR phase pw.envCounter = pw.envelope[2]; if (pw.envelope[2] > 0 && pw.envelope[1] < maxValue) { pw.envVolume = pw.envelope[1]; } else { pw.envVolume = maxValue; pw.envIndex++; } break; case 1: // DR phase pw.envCounter = pw.envelope[3]; if (pw.envelope[3] > 0 && pw.envelope[4] < maxValue) { pw.envVolume = maxValue; } else { pw.envVolume = pw.envelope[4]; pw.envIndex++; } break; case 2: // SR phase pw.envCounter = pw.envelope[5]; if (pw.envelope[5] > 0 && pw.envelope[4] != 0) { pw.envVolume = pw.envelope[4]; } else { pw.envVolume = 0; pw.envIndex = -1; } break; } } }
private int setEnvelopParamFromInstrument(partWork pw) { int n; if (!pw.getNum(out n)) { msgBox.setErrMsg("不正なエンベロープ番号が指定されています。", lineNumber); n = 0; } n = checkRange(n, 0, 255); if (!instENV.ContainsKey(n)) { msgBox.setErrMsg(string.Format("エンベロープ定義に指定された音色番号({0})が存在しません。", n), lineNumber); } else { if (pw.envInstrument != n) { pw.envInstrument = n; pw.envIndex = -1; pw.envCounter = -1; for (int i = 0; i < instENV[n].Length; i++) { pw.envelope[i] = instENV[n][i]; } } } return n; }
private void setAdpcmBPan(partWork pw, int pan) { if (pw.pan != pan) { outFmAdrPort(pw.port0, 0x11, (byte)((pan & 0x3) << 6)); pw.pan = pan; } }
private void setAdpcmBVolume(partWork pw) { int vol = pw.volume; if (pw.envelopeMode) { vol = 0; if (pw.envIndex != -1) { vol = pw.volume - (0xff - pw.envVolume); } } vol = checkRange(vol, 0, 0xff); if (pw.beforeVolume != vol) { outFmAdrPort(pw.port0, 0x1b, (byte)vol); pw.beforeVolume = pw.volume; } }
private void procLfo(partWork cpw) { //lfo処理 for (int lfo = 0; lfo < 4; lfo++) { clsLfo pl = cpw.lfo[lfo]; if (!pl.sw) { continue; } if (pl.waitCounter > 0)//== -1) { continue; } if (pl.type == eLfoType.Hardware) { if (cpw.chip is YM2612) { cpw.ams = pl.param[3]; cpw.fms = pl.param[2]; outOPNSetPanAMSFMS(cpw, cpw.pan, cpw.ams, cpw.fms); cpw.chip.lstPartWork[0].hardLfoSw = true; cpw.chip.lstPartWork[0].hardLfoNum = pl.param[1]; outOPNSetHardLfo(cpw, cpw.hardLfoSw, cpw.hardLfoNum); pl.waitCounter = -1; } continue; } switch (pl.param[4]) { case 0: //三角 pl.value += Math.Abs(pl.param[2]) * pl.direction; pl.waitCounter = pl.param[1]; if ((pl.direction > 0 && pl.value >= pl.param[3]) || (pl.direction < 0 && pl.value <= -pl.param[3])) { pl.value = pl.param[3] * pl.direction; pl.direction = -pl.direction; } break; case 1: //のこぎり pl.value += Math.Abs(pl.param[2]) * pl.direction; pl.waitCounter = pl.param[1]; if ((pl.direction > 0 && pl.value >= pl.param[3]) || (pl.direction < 0 && pl.value <= -pl.param[3])) { pl.value = -pl.param[3] * pl.direction; } break; case 2: //矩形 pl.value = pl.param[3] * pl.direction; pl.waitCounter = pl.param[1]; pl.direction = -pl.direction; break; case 3: //ワンショット pl.value += Math.Abs(pl.param[2]) * pl.direction; pl.waitCounter = pl.param[1]; if ((pl.direction > 0 && pl.value >= pl.param[3]) || (pl.direction < 0 && pl.value <= -pl.param[3])) { pl.waitCounter = -1; } break; case 4: //ランダム pl.value = rnd.Next(-pl.param[3], pl.param[3]); pl.waitCounter = pl.param[1]; break; } } }
private void procKeyOff(partWork pw) { if (pw.waitKeyOnCounter == 0) { if (pw.chip is YM2610B) { if (!pw.tie) { if (pw.ch < 9) outFmKeyOff(pw); else if (pw.Type == enmChannelType.SSG) { if (!pw.envelopeMode) { outSsgKeyOff(pw); } else { if (pw.envIndex != -1) { pw.envIndex = 3;//RR phase pw.envCounter = 0; } } } else if (pw.Type == enmChannelType.ADPCMA) { pw.keyOn = false; pw.keyOff = true; //((YM2610B)pw.chip).adpcmA_KeyOff |= (byte)(1 << (pw.ch - 12)); } else if (pw.Type == enmChannelType.ADPCMB) { if (!pw.envelopeMode) { outAdpcmBKeyOff(pw); } else { if (pw.envIndex != -1) { pw.envIndex = 3;//RR phase pw.envCounter = 0; } } } } } else if (pw.chip is YM2612) { if (!pw.tie) { outFmKeyOff(pw); } } else if (pw.chip is SN76489) { if (!pw.envelopeMode) { if (!pw.tie) outPsgKeyOff(pw); } else { if (pw.envIndex != -1) { if (!pw.tie) { pw.envIndex = 3;//RR phase pw.envCounter = 0; } } } } else { if (!pw.envelopeMode) { if (!pw.tie) outRf5c164KeyOff(pw); } else { if (pw.envIndex != -1) { if (!pw.tie) { pw.envIndex = 3;//RR phase pw.envCounter = 0; } } } } //次回に引き継ぎリセット pw.beforeTie = pw.tie; pw.tie = false; //ゲートタイムカウンターをリセット pw.waitKeyOnCounter = -1; } }
private void procEnvelope(partWork pw) { //Envelope処理 if ( (pw.chip is YM2610B && (pw.Type == enmChannelType.SSG || pw.Type == enmChannelType.ADPCMA || pw.Type == enmChannelType.ADPCMB)) || pw.chip is SN76489 || pw.chip is RF5C164 ) { envelope(pw); } if ((pw.chip is YM2610B && pw.ch < 6) || (pw.chip is YM2612)) { setFmFNum(pw); setFmVolume(pw); } else if (pw.chip is YM2610B && pw.Type == enmChannelType.SSG) { setSsgFNum(pw); setSsgVolume(pw); } else if (pw.chip is YM2610B && pw.Type == enmChannelType.ADPCMB) { setAdpcmBFNum(pw); setAdpcmBVolume(pw); } else if (pw.chip is SN76489) { if (pw.waitKeyOnCounter > 0 || pw.envIndex != -1) { setPsgFNum(pw); setPsgVolume(pw); } } else if (pw.chip is RF5C164) { if (pw.waitKeyOnCounter > 0 || pw.envIndex != -1) { setRf5c164FNum(pw); setRf5c164Volume(pw); } } }
private void setRf5c164Envelope(partWork pw, int volume) { if (pw.rf5c164Envelope != volume) { setRf5c164CurrentChannel(pw); byte data = (byte)(volume & 0xff); outRf5c164Port(pw.isSecondary, 0x0, data); pw.rf5c164Envelope = volume; } }
private void setFmFNum(partWork pw) { int[] ftbl = (pw.chip is YM2612) ? OPN_FNumTbl_7670454 : OPN_FNumTbl_8000000; int f = getFmFNum(ftbl, pw.octaveNow, pw.noteCmd, pw.shift + pw.keyShift);// if (pw.bendWaitCounter != -1) { f = pw.bendFnum; } int o = (f & 0xf000) / 0x1000; f &= 0xfff; f = f + pw.detune; for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Vibrato) { continue; } f += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } while (f < ftbl[0]) { if (o == 1) { break; } o--; f = ftbl[0] * 2 - (ftbl[0] - f); } while (f >= ftbl[0] * 2) { if (o == 8) { break; } o++; f = f - ftbl[0] * 2 + ftbl[0]; } f = checkRange(f, 0, 0x7ff); outFmSetFnum(pw, o, f); }
private void setRf5c164FNum(partWork pw) { int f = getRf5c164PcmNote(pw.octaveNow, pw.noteCmd, pw.keyShift + pw.shift);// if (pw.bendWaitCounter != -1) { f = pw.bendFnum; } f = f + pw.detune; for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Vibrato) { continue; } f += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } f = checkRange(f, 0, 0xffff); pw.freq = f; setRf5c164CurrentChannel(pw); //Address increment 再生スピードをセット setRf5c164AddressIncrement(pw, f); }
private void setFmVolume(partWork pw) { int vol = pw.volume; for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Tremolo) { continue; } vol += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } if (pw.beforeVolume != vol) { if (instFM.ContainsKey(pw.instrument)) { outFmSetVolume(pw, vol, pw.instrument); pw.beforeVolume = vol; } } }
private void setRf5c164Pan(partWork pw, int pan) { if (pw.rf5c164Pan != pan) { setRf5c164CurrentChannel(pw); byte data = (byte)(pan & 0xff); outRf5c164Port(pw.isSecondary, 0x1, data); pw.rf5c164Pan = pan; } }
private void setLfoAtKeyOn(partWork pw) { for (int lfo = 0; lfo < 4; lfo++) { clsLfo pl = pw.lfo[lfo]; if (!pl.sw) { continue; } if (pl.type == eLfoType.Hardware) { if (pw.chip is YM2612) { if (pl.param[4] == 1) { outOPNSetHardLfo(pw, false, pl.param[1]); pl.waitCounter = pl.param[0]; } } continue; } if (pl.param[5] != 1) { continue; } pl.isEnd = false; pl.value = (pl.param[0] == 0) ? pl.param[6] : 0;//ディレイ中は振幅補正は適用されない pl.waitCounter = pl.param[0]; pl.direction = pl.param[2] < 0 ? -1 : 1; if (pl.type == eLfoType.Vibrato) { if ((pw.chip is YM2610B) || (pw.chip is YM2612)) { setFmFNum(pw); } } if (pl.type == eLfoType.Tremolo) { if ((pw.chip is YM2610B) || (pw.chip is YM2612)) { pw.beforeVolume = -1; setFmVolume(pw); } } } }
private void setRf5c164Volume(partWork pw) { int vol = pw.volume; if (pw.envelopeMode) { vol = 0; if (pw.envIndex != -1) { vol = pw.envVolume - (255 - pw.volume); } } for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Tremolo) { continue; } vol += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } vol = checkRange(vol, 0, 255); if (pw.beforeVolume != vol) { setRf5c164Envelope(pw, vol); pw.beforeVolume = vol; } }
private void setPsgFNum(partWork pw) { if (pw.Type != enmChannelType.DCSGNOISE) { int f = getPsgFNum(pw.octaveNow, pw.noteCmd, pw.shift + pw.keyShift);// if (pw.bendWaitCounter != -1) { f = pw.bendFnum; } f = f + pw.detune; for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) { continue; } if (pw.lfo[lfo].type != eLfoType.Vibrato) { continue; } f += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } f = checkRange(f, 0, 0x3ff); if (pw.freq == f) return; pw.freq = f; byte data = 0; data = (byte)(0x80 + (pw.ch << 5) + (f & 0xf)); outPsgPort(pw.isSecondary, data); data = (byte)((f & 0x3f0) >> 4); outPsgPort(pw.isSecondary, data); } else { int f = pw.noise; byte data = (byte)(0xe0 + (f & 0x7)); pw.freq = 0x40 + (f & 7); } }
private void setSsgVolume(partWork pw) { byte pch = (byte)(pw.ch - 9); int vol = pw.volume; if (pw.envelopeMode) { vol = 0; if (pw.envIndex != -1) { vol = pw.volume - (15 - pw.envVolume); } } vol = checkRange(vol, 0, 15); if (pw.beforeVolume != vol) { outFmAdrPort(pw.port0, (byte)(0x08 + pch), (byte)vol); pw.beforeVolume = pw.volume; } }
private void setPsgVolume(partWork pw) { byte data = 0; int vol = pw.volume; if (pw.envelopeMode) { vol = 0; if (pw.envIndex != -1) { vol = pw.envVolume - (15 - pw.volume); } } for (int lfo = 0; lfo < 4; lfo++) { if (!pw.lfo[lfo].sw) continue; if (pw.lfo[lfo].type != eLfoType.Tremolo) continue; vol += pw.lfo[lfo].value + pw.lfo[lfo].param[6]; } vol = checkRange(vol, 0, 15); if (pw.beforeVolume != vol) { data = (byte)(0x80 + (pw.ch << 5) + 0x10 + (15 - vol)); outPsgPort(pw.isSecondary, data); pw.beforeVolume = vol; } }
private void setYM2610BADPCMBAddress(partWork pw, int startAdr, int endAdr) { if (pw.pcmStartAddress != startAdr) { outFmAdrPort(pw.port0, 0x12, (byte)((startAdr >> 8) & 0xff)); outFmAdrPort(pw.port0, 0x13, (byte)((startAdr >> 16) & 0xff)); pw.pcmStartAddress = startAdr; } if (pw.pcmEndAddress != endAdr) { outFmAdrPort(pw.port0, 0x14, (byte)(((endAdr - 0x100) >> 8) & 0xff)); outFmAdrPort(pw.port0, 0x15, (byte)(((endAdr - 0x100) >> 16) & 0xff)); pw.pcmEndAddress = endAdr; } //outFmAdrPort(pw.port1, 0x01, 0x3f); //outFmAdrPort(pw.port1, 0x08, 0xdf); //outFmAdrPort(pw.port1, 0x00, 0x01); }
private void setRf5c164AddressIncrement(partWork pw, int f) { if (pw.rf5c164AddressIncrement != f) { byte data = (byte)(f & 0xff); outRf5c164Port(pw.isSecondary, 0x2, data); data = (byte)((f >> 8) & 0xff); outRf5c164Port(pw.isSecondary, 0x3, data); pw.rf5c164AddressIncrement = f; } }
private void cmdClockLength(partWork pw) { int n; pw.incPos(); if (!pw.getNum(out n)) { msgBox.setErrMsg("不正な音長が指定されています。", lineNumber); n = 10; } n = checkRange(n, 1, 65535); pw.length = n; }
private void setRf5c164CurrentChannel(partWork pw) { byte pch = (byte)pw.ch; bool isSecondary = pw.isSecondary; int chipID = pw.chip.ChipID; if (rf5c164[chipID].CurrentChannel != pch) { byte data = (byte)(0xc0 + pch); outRf5c164Port(isSecondary, 0x7, data); rf5c164[chipID].CurrentChannel = pch; } }
private void cmdEnvelope(partWork pw) { int n = -1; if ( ((pw.chip is YM2610B) && (pw.Type == enmChannelType.SSG || pw.Type == enmChannelType.FMOPNex)) || ((pw.chip is YM2612) && (pw.Type == enmChannelType.FMPCM || (pw.Type == enmChannelType.FMOPNex))) || (pw.chip is SN76489) || (pw.chip is RF5C164) ) { pw.incPos(); switch (pw.getChar()) { case 'O': pw.incPos(); if ( ((pw.chip is YM2610B) && pw.Type == enmChannelType.FMOPNex) || pw.chip is YM2612 ) { switch (pw.getChar()) { case 'N': pw.incPos(); pw.Ch3SpecialMode = true; outOPNSetCh3SpecialMode(pw, true); break; case 'F': pw.incPos(); pw.Ch3SpecialMode = false; outOPNSetCh3SpecialMode(pw, false); break; default: msgBox.setErrMsg(string.Format("未知のコマンド(EO{0})が指定されました。", pw.getChar()), lineNumber); pw.incPos(); break; } } else { switch (pw.getChar()) { case 'N': pw.incPos(); pw.envelopeMode = true; break; case 'F': pw.incPos(); pw.envelopeMode = false; break; default: msgBox.setErrMsg(string.Format("未知のコマンド(EO{0})が指定されました。", pw.getChar()), lineNumber); pw.incPos(); break; } } break; case 'X': char c = pw.getChar(); if ( ((pw.chip is YM2610B) && pw.Type == enmChannelType.FMOPNex) || pw.chip is YM2612 ) { pw.incPos(); if (!pw.getNum(out n)) { msgBox.setErrMsg("不正なスロット指定'EX'が指定されています。", lineNumber); n = 0; } byte res = 0; while (n % 10 != 0) { if (n % 10 > 0 && n % 10 < 5) { res += (byte)(1 << (n % 10 - 1)); } else { msgBox.setErrMsg(string.Format("未知のコマンド(EX{0})が指定されました。", n), lineNumber); break; } n /= 10; } if (res != 0) { pw.slots = res; } } else { msgBox.setErrMsg("未知のコマンド(EX)が指定されました。", lineNumber); } break; default: if (pw.Type == enmChannelType.FMOPNex) { int[] s = new int[] { 0, 0, 0, 0 }; for (int i = 0; i < 4; i++) { if (pw.getNum(out n)) { s[i] = n; } else { msgBox.setErrMsg("Eコマンドの解析に失敗しました。", lineNumber); break; } if (i == 3) break; pw.incPos(); } pw.slotDetune = s; break; } else { msgBox.setErrMsg(string.Format("未知のコマンド(E{0})が指定されました。", pw.getChar()), lineNumber); pw.incPos(); } break; } } else { msgBox.setWrnMsg("このパートは効果音モードに対応したチャンネルが指定されていないため、Eコマンドは無視されます。", lineNumber); pw.incPos(); } }
private void outYM2612SetCh6PCMMode(partWork pw, bool sw) { dat.Add(pw.port0); dat.Add(0x2b); dat.Add((byte)((sw ? 0x80 : 0))); }