public class CMusicLine // Hungarian: mln { final int BST_NO_NOTE=0; // No note on this beat final int BST_WHISPER=1; final int BST_LIGHT=2; // Faint note final int BST_MEDIUM=3; // Normal note final int BST_HEAVY=4; // Emphsized note final int BST_BANG=5; final int KP_ROOT = 0; final int KP_PRIMARY = 1; // "required"? final int KP_SECONDARY = 2; // "auxiliary"? final int KP_TERTIARY = 3; // "modal"? final int KP_CHROMATIC = 4; final char MID_C = 60; // Members CCompoundMusicLine m_pcmlParent; CLayer m_plyrParent; char m_pvCenterNoteNum; CNote m_arrpNotesPlayed[]; // Assume sorted by the iBeatNum field. int m_iNumNotesPlayed; int m_iNumNotesAllocated; //======bogus global functions===== public int mod (int x, int y) { if (x>=0) return x%y; int iNegMod = (-x) % y; return (0==iNegMod) ? y-iNegMod : 0; } public void assert(boolean b) { if (!b) m_arrpNotesPlayed[-1] = null; } public int rand() { return (int)(Math.random() * 9747); } //================================ public CNote pNoteToPlay (int iCurrBeatNum, CLineMods plm/*=0*/) { // If a note has already been played at this beat number: if (m_iNumNotesPlayed > 0 && m_arrpNotesPlayed [m_iNumNotesPlayed-1].iBeatNum == iCurrBeatNum) { return null; } if (!m_plyrParent.bActive()) return null; CRthmMods rm = new CRthmMods(m_plyrParent.rymodRthmStatus(), m_plyrParent.fRthmStatusArg()); rm.bCadence = m_pcmlParent.bDoCadence(); rm.pvCoherence = m_pcmlParent.pvGetCohesion(); // See if the rhythm says it's time for a note: CRhythm rthm = rthmGetRhythm(); double fPos = rthm.fPosition(iCurrBeatNum, rm); if (fPos <= 0) { return null; } int bst; int iDuration = 0; bst = rthm.bstGetBeatStatus(iCurrBeatNum, rm, iDuration); iDuration = rthm.bogus_piDuration; if (bst == BST_NO_NOTE) return null; // Find a tentative note. Either by copying or generating: boolean bCopy = false; if (plm!=null && plm.pCopyLine!=null) { int iCopyLen = plm.pCopyLine.iGetNumNotesPlayed(); if (iCopyLen > m_iNumNotesPlayed) { if (plm.iCopyIndex >= iCopyLen/2) { if (m_iNumNotesPlayed <= plm.iCopyIndex) bCopy = true; } else if (plm.iCopyIndex <= m_iNumNotesPlayed) bCopy = true; } } if (bCopy) m_pvCenterNoteNum = pvCopyLine(plm); else m_pvCenterNoteNum = pvGenerate(m_pvCenterNoteNum, iDuration*10/rthm.iAveDuration()); // Ok, we have a tentative note. Now see if we want to // tweak it: if (rthm.bLastNote(iCurrBeatNum, rm)) { // Final note of line, so make it coherent: int kpRound = m_pcmlParent.bDoCadence() ? KP_ROOT : KP_PRIMARY; m_pvCenterNoteNum = (char)sclGetScale().iRoundNoteNum( m_pvCenterNoteNum, kpRound, pvGetKey()); //tw.spr("%x Last %d: %.2f\n", this, iCurrBeatNum, // rthm.fPosition(iCurrBeatNum, rm)); } else { if (plm!=null && plm.bContrast) m_pvCenterNoteNum = pvContrast(m_pvCenterNoteNum); else if (m_plyrParent.bMatchChord()) m_pvCenterNoteNum = pvMatchChord(m_pvCenterNoteNum); } if (m_pvCenterNoteNum < 0) m_pvCenterNoteNum = 0; else if (m_pvCenterNoteNum > 127) m_pvCenterNoteNum = 127; AppendPlayedNote(iCurrBeatNum, m_pvCenterNoteNum, bst, iDuration); assert(iDuration > 0 && iDuration < 1000); CSection sec = m_pcmlParent.m_pstzParent.m_psecParent; assert(sec.sm_iNumActiveNotes != sec.MAX_ACTIVE_NOTES); sec.sm_arrNotesActive[sec.sm_iNumActiveNotes] = (m_arrpNotesPlayed[m_iNumNotesPlayed-1]); sec.sm_iNumActiveNotes++; return m_arrpNotesPlayed[m_iNumNotesPlayed-1]; } //------------------------------------- public CNote pNoteToEnd (int iCurrBeatNum) { CSection sec = m_pcmlParent.m_pstzParent.m_psecParent; for (int C=0; C iCurrBeatNum && pNote2.pvInstrument == pNote.pvInstrument) { bWait = true; pNote.iDuration = pNote2.iBeatNum + pNote2.iDuration - pNote.iBeatNum; } } if (bWait) continue; // Otherwise, confirm this note off. sec.sm_iNumActiveNotes--; if (C != sec.sm_iNumActiveNotes) { CNote noteTemp = sec.sm_arrNotesActive[C]; sec.sm_arrNotesActive[C] = sec.sm_arrNotesActive[sec.sm_iNumActiveNotes]; // Put dead note at end temporarily so we can point at it. sec.sm_arrNotesActive[sec.sm_iNumActiveNotes] = noteTemp; } //TRACE("%d[%d]=%d ", sec.sm_iNumActiveNotes, C, sec.sm_arrNotesActive[0].iBeatNum); return sec.sm_arrNotesActive[sec.sm_iNumActiveNotes]; } } if (sec.sm_iNumActiveNotes*2 >= sec.MAX_ACTIVE_NOTES) { sec.sm_iNumActiveNotes--; return sec.sm_arrNotesActive[sec.sm_iNumActiveNotes]; } return null; } //------------------------------------- public boolean bDonePlaying (int iCurrBeatNum) { if (!m_plyrParent.bActive()) return true; CRthmMods rm = new CRthmMods(m_plyrParent.rymodRthmStatus(), m_plyrParent.fRthmStatusArg()); rm.bCadence = m_pcmlParent.bDoCadence(); rm.pvCoherence = m_pcmlParent.pvGetCohesion(); return (rthmGetRhythm().iOutside(iCurrBeatNum, rm) > 0); } public CRhythm rthmGetRhythm () { return m_plyrParent.pRhythm(); } public CScale sclGetScale() { return m_plyrParent.Scale(); } public char pvGetCenterNote () { return m_pvCenterNoteNum; } public void SetCenterNote (char pvNoteNum) { m_pvCenterNoteNum = pvNoteNum; } public int iGetNumNotesPlayed () { return m_iNumNotesPlayed; } public CNote pGetPlayedNote (int index) { assert(0<=index && index 20 && kp > KP_PRIMARY && mod(rnd1^rnd2,2)!=0) kp = (int)(kp-1); double fRand = 7.0 / (double)(1 + mod(rnd2,7)); int ret = (int)(mod(rnd1^rnd2,128) > m_plyrParent.pvDirection() ? pvRef-fRand-.5 : pvRef+fRand+.5); assert(null!=m_plyrParent); assert(null!=sclGetScale()); return (char)sclGetScale().iRoundNoteNum(ret, kp, pvGetKey()); } //------------------------------------- char pvContrast (char pvRef) { int kpRound = mod(rand(),3)!=0 ? KP_SECONDARY : KP_PRIMARY; // Assuming there ARE 2ndary notes! return (char) sclGetScale().iRoundNoteNum(pvRef, kpRound, pvGetKey()); } //------------------------------------- char pvMatchChord (char pvCurrNoteNum) { // Find the last melodic note that was played: CMusicLine pmlnMelody = m_pcmlParent.pmlnGetLine(0); if (pmlnMelody != null) { int iPrevMelIndex = pmlnMelody.iGetNumNotesPlayed() - 1; if (iPrevMelIndex >= 0) { CNote pnotePrevMel = pmlnMelody.pGetPlayedNote(iPrevMelIndex); // Find nearest note with same int: return (char) sclGetScale().iMatchNearestChord( pvCurrNoteNum, sclGetScale().kpGetPriority( pnotePrevMel.iNoteNum, pvGetKey()), pvGetKey()); } } return pvCurrNoteNum; } } // end CMusicLine