home *** CD-ROM | disk | FTP | other *** search
/ Internet 1996 World Exposition / park.org.s3.amazonaws.com.7z / park.org.s3.amazonaws.com / Cdrom / Pavilions / BrainOpera / online / net-music / net-instrument / CMusicLine.java < prev    next >
Encoding:
Java Source  |  2017-09-21  |  8.9 KB  |  267 lines

  1. public class CMusicLine    // Hungarian: mln
  2. {
  3.     final int BST_NO_NOTE=0;    // No note on this beat
  4.     final int BST_WHISPER=1;
  5.     final int BST_LIGHT=2;    // Faint note
  6.     final int BST_MEDIUM=3;    // Normal note
  7.     final int BST_HEAVY=4;    // Emphsized note
  8.     final int BST_BANG=5;
  9.     final int KP_ROOT = 0;
  10.     final int KP_PRIMARY = 1;    // "required"?
  11.     final int KP_SECONDARY = 2;    // "auxiliary"?
  12.     final int KP_TERTIARY = 3;    // "modal"?
  13.     final int KP_CHROMATIC = 4;
  14.     final char MID_C = 60;
  15. // Members
  16.     CCompoundMusicLine m_pcmlParent;
  17.     CLayer m_plyrParent;
  18.     
  19.     char m_pvCenterNoteNum;
  20.     
  21.     CNote m_arrpNotesPlayed[];    // Assume sorted by the iBeatNum field.
  22.     int m_iNumNotesPlayed;
  23.     int m_iNumNotesAllocated;
  24.  
  25. //======bogus global functions=====
  26. public int mod (int x, int y)
  27. {    if (x>=0) return x%y;
  28.     int iNegMod = (-x) % y;
  29.     return (0==iNegMod) ? y-iNegMod : 0;
  30. }
  31. public void assert(boolean b) { if (!b) m_arrpNotesPlayed[-1] = null; }
  32. public int rand() { return (int)(Math.random() * 9747); }
  33. //================================
  34.  
  35. public CNote pNoteToPlay (int iCurrBeatNum,
  36.         CLineMods plm/*=0*/)
  37. {    // If a note has already been played at this beat number:
  38.     if (m_iNumNotesPlayed > 0 && m_arrpNotesPlayed
  39.         [m_iNumNotesPlayed-1].iBeatNum == iCurrBeatNum) {
  40.         return null;
  41.     }
  42.     if (!m_plyrParent.bActive())
  43.         return null;
  44.  
  45.     CRthmMods rm = new CRthmMods(m_plyrParent.rymodRthmStatus(),
  46.         m_plyrParent.fRthmStatusArg());
  47.     rm.bCadence = m_pcmlParent.bDoCadence();
  48.     rm.pvCoherence = m_pcmlParent.pvGetCohesion();
  49.     
  50.     // See if the rhythm says it's time for a note:
  51.     CRhythm rthm = rthmGetRhythm();
  52.     double fPos = rthm.fPosition(iCurrBeatNum, rm);
  53.     if (fPos <= 0) {
  54.         return null;
  55.     }
  56.  
  57.     int bst;
  58.     int iDuration = 0;
  59.     bst = rthm.bstGetBeatStatus(iCurrBeatNum, rm, iDuration);
  60.     iDuration = rthm.bogus_piDuration;
  61.     if (bst == BST_NO_NOTE)
  62.         return null;
  63.  
  64.     // Find a tentative note. Either by copying or generating:
  65.     boolean bCopy = false;
  66.     if (plm!=null && plm.pCopyLine!=null) {
  67.         int iCopyLen = plm.pCopyLine.iGetNumNotesPlayed();
  68.         if (iCopyLen > m_iNumNotesPlayed) {
  69.             if (plm.iCopyIndex >= iCopyLen/2) {
  70.                 if (m_iNumNotesPlayed <= plm.iCopyIndex)
  71.                     bCopy = true;
  72.             } else if (plm.iCopyIndex <= m_iNumNotesPlayed)
  73.                 bCopy = true;
  74.         }
  75.     }
  76.     if (bCopy)
  77.         m_pvCenterNoteNum = pvCopyLine(plm);
  78.     else m_pvCenterNoteNum = pvGenerate(m_pvCenterNoteNum,
  79.         iDuration*10/rthm.iAveDuration());
  80.     
  81.     // Ok, we have a tentative note. Now see if we want to
  82.     // tweak it:
  83.     if (rthm.bLastNote(iCurrBeatNum, rm))
  84.     {    // Final note of line, so make it coherent:
  85.         int kpRound = m_pcmlParent.bDoCadence() ?
  86.             KP_ROOT : KP_PRIMARY;
  87.         m_pvCenterNoteNum = (char)sclGetScale().iRoundNoteNum(
  88.             m_pvCenterNoteNum, kpRound, pvGetKey());
  89.         //tw.spr("%x Last %d: %.2f\n", this, iCurrBeatNum,
  90.         //    rthm.fPosition(iCurrBeatNum, rm));
  91.     } else
  92.     {    if (plm!=null && plm.bContrast)
  93.                 m_pvCenterNoteNum = pvContrast(m_pvCenterNoteNum);
  94.         else if (m_plyrParent.bMatchChord())
  95.             m_pvCenterNoteNum = pvMatchChord(m_pvCenterNoteNum);
  96.     }
  97.  
  98.     if (m_pvCenterNoteNum < 0)
  99.         m_pvCenterNoteNum = 0;
  100.     else if (m_pvCenterNoteNum > 127)
  101.         m_pvCenterNoteNum = 127;
  102.     AppendPlayedNote(iCurrBeatNum, m_pvCenterNoteNum, bst, iDuration);
  103.     assert(iDuration > 0 && iDuration < 1000);
  104.     CSection sec = m_pcmlParent.m_pstzParent.m_psecParent;
  105.     assert(sec.sm_iNumActiveNotes != sec.MAX_ACTIVE_NOTES);
  106.     sec.sm_arrNotesActive[sec.sm_iNumActiveNotes] =
  107.         (m_arrpNotesPlayed[m_iNumNotesPlayed-1]);
  108.     sec.sm_iNumActiveNotes++;
  109.     return m_arrpNotesPlayed[m_iNumNotesPlayed-1];
  110. }
  111.  
  112. //-------------------------------------
  113.  
  114. public CNote pNoteToEnd (int iCurrBeatNum)
  115. {
  116.     CSection sec = m_pcmlParent.m_pstzParent.m_psecParent;
  117.     for (int C=0; C<sec.sm_iNumActiveNotes; C++) {
  118.         CNote pNote = sec.sm_arrNotesActive[C];
  119.         if (pNote.iBeatNum + pNote.iDuration <= iCurrBeatNum) {
  120.             // First check to see if a duplicate of this note will be on.
  121.             // If so, then delay this note off.
  122.             boolean bWait = false;
  123.             for (int i=0; i<sec.sm_iNumActiveNotes; i++) {
  124.                 CNote pNote2 = sec.sm_arrNotesActive[i];
  125.                 if (pNote2.iNoteNum == pNote.iNoteNum &&
  126.                     pNote2.iBeatNum + pNote2.iDuration > iCurrBeatNum &&
  127.                     pNote2.pvInstrument == pNote.pvInstrument) {
  128.                     bWait = true;
  129.                     pNote.iDuration = pNote2.iBeatNum + pNote2.iDuration
  130.                         - pNote.iBeatNum;
  131.                 }
  132.             }
  133.             if (bWait)
  134.                 continue;
  135.  
  136.             // Otherwise, confirm this note off.
  137.             sec.sm_iNumActiveNotes--;
  138.             if (C != sec.sm_iNumActiveNotes) {
  139.                 CNote noteTemp = sec.sm_arrNotesActive[C];
  140.                 sec.sm_arrNotesActive[C] = sec.sm_arrNotesActive[sec.sm_iNumActiveNotes];
  141.                 // Put dead note at end temporarily so we can point at it.
  142.                 sec.sm_arrNotesActive[sec.sm_iNumActiveNotes] = noteTemp;
  143.             }
  144.             //TRACE("%d[%d]=%d ", sec.sm_iNumActiveNotes, C, sec.sm_arrNotesActive[0].iBeatNum);
  145.             return sec.sm_arrNotesActive[sec.sm_iNumActiveNotes];
  146.         }
  147.     }
  148.     if (sec.sm_iNumActiveNotes*2 >= sec.MAX_ACTIVE_NOTES) {
  149.         sec.sm_iNumActiveNotes--;
  150.         return sec.sm_arrNotesActive[sec.sm_iNumActiveNotes];
  151.     }
  152.     return null;
  153. }
  154.  
  155. //-------------------------------------
  156. public boolean bDonePlaying (int iCurrBeatNum)
  157. {    if (!m_plyrParent.bActive()) return true;
  158.     CRthmMods rm = new CRthmMods(m_plyrParent.rymodRthmStatus(),
  159.         m_plyrParent.fRthmStatusArg());
  160.     rm.bCadence = m_pcmlParent.bDoCadence();
  161.     rm.pvCoherence = m_pcmlParent.pvGetCohesion();
  162.     return (rthmGetRhythm().iOutside(iCurrBeatNum, rm) > 0);
  163. }
  164.  
  165.     public CRhythm rthmGetRhythm () { return m_plyrParent.pRhythm(); }
  166.     public CScale sclGetScale() { return m_plyrParent.Scale(); }
  167.  
  168.     public char pvGetCenterNote () { return m_pvCenterNoteNum; }
  169.     public void SetCenterNote (char pvNoteNum)
  170.     { m_pvCenterNoteNum = pvNoteNum; }
  171.  
  172.     public int iGetNumNotesPlayed () { return m_iNumNotesPlayed; }
  173.     public CNote pGetPlayedNote (int index)
  174.     {    assert(0<=index && index<m_iNumNotesPlayed);
  175.         return m_arrpNotesPlayed[index];
  176.     }
  177.  
  178.     public char pvGetKey ()
  179.     {    return m_pcmlParent.pvGetKey(); }
  180.         
  181. // Construction/Destruction
  182. //-------------------------------------
  183. CMusicLine (CCompoundMusicLine pcmlParent,
  184.     CLayer plyrParent)
  185. {    m_pcmlParent=pcmlParent;
  186.     m_plyrParent=plyrParent;
  187.     m_pvCenterNoteNum=MID_C;
  188.     m_arrpNotesPlayed=null; m_iNumNotesPlayed=0;
  189.     m_iNumNotesAllocated=0;
  190. }
  191.     
  192. // Implementation
  193. //-------------------------------------
  194. void AppendPlayedNote (int iBeatNum, int iNoteNum,
  195.         int bstStress, int iDuration)
  196. {
  197.     if (m_iNumNotesPlayed == m_iNumNotesAllocated)
  198.     {
  199.         m_iNumNotesAllocated += 10;
  200.         CNote[] temp = m_arrpNotesPlayed;
  201.         m_arrpNotesPlayed = new CNote[m_iNumNotesAllocated];
  202.         for(int C=0; C<m_iNumNotesAllocated-10; C++)
  203.             m_arrpNotesPlayed[C] = temp[C];
  204.     }
  205.     m_iNumNotesPlayed++;
  206.     m_arrpNotesPlayed[m_iNumNotesPlayed-1] = new CNote();
  207.     m_arrpNotesPlayed[m_iNumNotesPlayed-1].iBeatNum = iBeatNum;
  208.     m_arrpNotesPlayed[m_iNumNotesPlayed-1].iNoteNum = iNoteNum;
  209.     m_arrpNotesPlayed[m_iNumNotesPlayed-1].bstStress = bstStress;
  210.     m_arrpNotesPlayed[m_iNumNotesPlayed-1].iDuration = iDuration;
  211.     m_arrpNotesPlayed[m_iNumNotesPlayed-1].pvInstrument =
  212.         m_plyrParent.pvInstrument();
  213. }
  214. //-------------------------------------
  215. // Breaking up pNoteToPlay to modular pieces:
  216. char pvCopyLine (CLineMods plm)
  217. {    int iOldNoteNum = plm.pCopyLine.
  218.             pGetPlayedNote(m_iNumNotesPlayed).iNoteNum;
  219.     int kp = (int)(KP_CHROMATIC -
  220.         (int)((double)(rand()%100)/100.0 +
  221.             (double)(m_plyrParent.pvConsonance()) * 4.0 / 128.0));
  222.     return (char)sclGetScale().iRoundNoteNum(iOldNoteNum + plm.iCLOffset,
  223.         kp, pvGetKey());
  224. }
  225.  
  226. //-------------------------------------
  227. char pvGenerate (char pvRef, int iNoteLen)
  228. {    int rnd1 = rand(), rnd2 = rand();
  229.     int kp = (int)(KP_CHROMATIC -
  230.         (int)((double)(rnd1%100)/100.0 +
  231.             (double)(m_plyrParent.pvConsonance()) * 4.0 / 128.0));
  232.     if (iNoteLen > 20 && kp > KP_PRIMARY && mod(rnd1^rnd2,2)!=0)
  233.         kp = (int)(kp-1);
  234.     double fRand = 7.0 / (double)(1 + mod(rnd2,7));
  235.     int ret = (int)(mod(rnd1^rnd2,128) > m_plyrParent.pvDirection() ?
  236.         pvRef-fRand-.5 : pvRef+fRand+.5);
  237.     assert(null!=m_plyrParent);
  238.     assert(null!=sclGetScale());
  239.     return (char)sclGetScale().iRoundNoteNum(ret, kp, pvGetKey());
  240. }
  241.  
  242. //-------------------------------------
  243. char pvContrast (char pvRef)
  244. {    int kpRound = mod(rand(),3)!=0 ? KP_SECONDARY :
  245.         KP_PRIMARY;    // Assuming there ARE 2ndary notes!
  246.     return (char) sclGetScale().iRoundNoteNum(pvRef, kpRound, pvGetKey());
  247. }
  248. //-------------------------------------
  249. char pvMatchChord (char pvCurrNoteNum)
  250. {    // Find the last melodic note that was played:
  251.     CMusicLine pmlnMelody = m_pcmlParent.pmlnGetLine(0);
  252.     if (pmlnMelody != null)
  253.     {    int iPrevMelIndex = pmlnMelody.iGetNumNotesPlayed() - 1;
  254.         if (iPrevMelIndex >= 0)
  255.         {    CNote pnotePrevMel =
  256.                 pmlnMelody.pGetPlayedNote(iPrevMelIndex);
  257.             // Find nearest note with same int:
  258.             return (char) sclGetScale().iMatchNearestChord(
  259.                 pvCurrNoteNum, sclGetScale().kpGetPriority(
  260.                 pnotePrevMel.iNoteNum, pvGetKey()), pvGetKey());
  261.         }
  262.     }
  263.     return pvCurrNoteNum;
  264. }
  265.  
  266. }    // end CMusicLine
  267.