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 / CRhythm.java < prev    next >
Encoding:
Java Source  |  2017-09-21  |  14.1 KB  |  432 lines

  1. /*typedef enum
  2. {
  3.     final int RYMOD_CONSTANT=0;
  4.     final int RYMOD_BETWEEN=1;
  5.     final int RYMOD_PERIODIC=2;
  6.     final int RYMOD_NONE=3;
  7.     final int NUM_RYMODS=4;
  8. }    RthmModify;    // Hungarian: rymod
  9. */
  10.  
  11. //----------------------------------------------------------
  12. import java.applet.Applet;
  13.  
  14. class CRhythm extends Applet    // Hungarian: rthm
  15. {
  16.     int bogus_piDuration;    // Bogus return value.
  17.  
  18.     // constants
  19.     final int RYMOD_CONSTANT=0;
  20.     final int RYMOD_BETWEEN=1;
  21.     final int RYMOD_PERIODIC=2;
  22.     final int RYMOD_NONE=3;
  23.     final int NUM_RYMODS=4;
  24.     final int BST_NO_NOTE=0;    // No note on this beat
  25.     final int BST_WHISPER=1;
  26.     final int BST_LIGHT=2;    // Faint note
  27.     final int BST_MEDIUM=3;    // Normal note
  28.     final int BST_HEAVY=4;    // Emphsized note
  29.     final int BST_BANG=5;
  30.     final double fMIN_NUMSLOTS =6.0;
  31.     final double fMAX_NUMSLOTS =64.0;
  32.     final double fMIN_DENSITY =.1;
  33.     final double fMAX_DENSITY =1.0;
  34.     final double fMIN_CONSISTENCY =.3;
  35.     final double fMAX_CONSISTENCY =1.0;
  36. // Members
  37.     int m_iLastBeatNum;        // When was the last time we were played?
  38.     int m_iLastIndexPlayed;    // What was the last note we returned?
  39.     char m_pvTempo;    // This name is actually misleading.
  40.         // The larger this value is, the slower we go. See
  41.         // GetBeatNum and bstGetConstantStatus.
  42.     
  43.     int m_iNumNotes;    // Number of notes actually played in an
  44.         // occurence of this rhythm/meter.
  45.     int m_iNumAllocated;
  46.     int m_arriNoteBeatNums[];    // Array of beat numbers: one for
  47.         // each of the notes to play, where m_arriNoteBeatNums[2]=3
  48.         // means the 2nd note will be played on the (3*m_pvTempo)'th
  49.         // beat of the rhythm.
  50.         // Assume beat numbers are in ascending order.
  51.     int m_arrbstNoteStresses[];    // Array of stresses: one
  52.         // for each of the notes to play.
  53.  
  54.     // The following chars are used for generating new rhythms.
  55.     // None of these values specifically refer to a number, instead
  56.     // they map into the range of allowable values. 0 for minimum,
  57.     // 127 for max, 63-64 in the middle.
  58.     char m_pvDensity;    // What ratio of slots to fill.
  59.     char m_pvLength;    // How many slots to have available.
  60.         // Directly proportional to periodicity.
  61.     char m_pvConsistency;    // Amount of repetition.
  62.  
  63. //===============================================
  64. public int mod (int x, int y)
  65. {    if (x>=0) return x%y;
  66.     int iNegMod = (-x) % y;
  67.     return (0==iNegMod) ? y-iNegMod : 0;
  68. }
  69. public void assert(boolean b) { if (!b) m_arrbstNoteStresses[-1] = 0; }
  70. public int rand() { return (int)(Math.random() * 9747); }
  71.  
  72. // Operations
  73.     // Set when this occurence of the rhythm/meter will begin.
  74.     void SetFirstBeat (int iBeatNum)
  75.     { m_iLastBeatNum = iBeatNum; m_iLastIndexPlayed = -1; }
  76.  
  77. int bstGetBeatStatus (int iCurrBeatNum,
  78.     CRthmMods prmods, int piDuration)
  79. {    bogus_piDuration = 0;
  80.     assert(m_iNumNotes > 0);
  81.     // For cadence, slowly become twice as slow by end of rhythm
  82.     // (for now).
  83.     char pvOldTempo = 0;
  84.     boolean bCadence = /*prmods &&*/ prmods.bCadence;
  85.     if (bCadence)
  86.     {    pvOldTempo = m_pvTempo;
  87.         double fRatio = ((double)m_iLastIndexPlayed+1)/
  88.             ((double)m_iNumNotes);
  89.         if (fRatio < .0) fRatio = .0;
  90.         else if (fRatio > 1.0) fRatio = 1.0;
  91.         m_pvTempo = (char)(((double)m_pvTempo) * (fRatio+1.0) + .5);
  92.         //tw.spr("GBS: %d(%d) -> %d\r", iBeatNum, pvOldTempo, m_pvTempo);
  93.     }
  94.     int iBeatNum = iCurrBeatNum - m_iLastBeatNum;
  95.     if (m_iLastIndexPlayed != -1)
  96.         iBeatNum += GetBeatNum(m_iLastIndexPlayed);
  97.     assert(iBeatNum >= 0);
  98.  
  99.     int ret = -1;
  100.     switch (prmods.rymod)
  101.     {    case RYMOD_CONSTANT:
  102.             ret = bstGetConstantStatus(iBeatNum, prmods.fRMArg, piDuration);
  103.             break;
  104.         case RYMOD_BETWEEN:
  105.             ret = bstGetBetweenStatus(iBeatNum, prmods.fRMArg, piDuration);
  106.             break;
  107.         case RYMOD_PERIODIC:
  108.             ret = bstGetPeriodicStatus(iBeatNum, prmods.fRMArg, piDuration);
  109.             break;
  110.         case RYMOD_NONE:
  111.             ret = bstGetNormalStatus(iBeatNum, piDuration);
  112.             // How about a volume change for normal cadence?
  113.             if (bCadence)
  114.             {    if (ret != BST_NO_NOTE && ret != BST_BANG)
  115.                     ret = (ret+1);
  116.             }
  117.             break;
  118.         default: assert(false); break;
  119.     }
  120.     
  121.     // Should we randomly insert a note where one shouldn't be?
  122.     if (ret == BST_NO_NOTE && iBeatNum%m_pvTempo == 0) {
  123.         double fRand = ((double)m_arriNoteBeatNums[m_iNumNotes-1] -
  124.             m_arriNoteBeatNums[0]);
  125.         fRand *= (double)(prmods.pvCoherence)*6.0/127.0;
  126.         if (fRand < 1.0) fRand = 1.0;
  127.         if (mod(rand(), (int)(fRand + .5)) == 0) {
  128.             ret = BST_LIGHT;
  129.         }
  130.     }
  131.                 
  132.     // Return speed to normal.
  133.     if (bCadence)
  134.     {    m_pvTempo = pvOldTempo;
  135.     }
  136.  
  137.     if (ret != BST_NO_NOTE && bogus_piDuration == 0)
  138.         bogus_piDuration = m_pvTempo;
  139.  
  140.     return ret;
  141. }
  142.  
  143.     // Return -1 if the given beat number is before the current
  144.     // iteration of the rhythm; 0 if it fits within; 1 if it
  145.     // occurs after.
  146.     public int iOutside (int iBeatNum, CRthmMods prmods/*=0*/)
  147.     {
  148.         double fPos = fPosition(iBeatNum, prmods);
  149.         if (fPos <= 0) return -1;
  150.         if (fPos <= 1) return 0;
  151.         return 1;
  152.     }
  153.  
  154. public double fPosition (int iCurrBeatNum,
  155.     CRthmMods prmods/*=0*/)
  156. {
  157.     // For cadence, slowly become twice as slow by end of rhythm
  158.     // (for now).
  159.     assert(m_iNumNotes > 0);
  160.     char pvOldTempo = 0;
  161.     boolean bCadence = /*prmods && */prmods.bCadence;
  162.     if (bCadence)
  163.     {    pvOldTempo = m_pvTempo;
  164.         double fRatio = (double)(m_iLastIndexPlayed+1)/
  165.             (double)(m_iNumNotes);
  166.         if (fRatio < .0) fRatio = .0;
  167.         else if (fRatio > 1.0) fRatio = 1.0;
  168.         m_pvTempo = (char)((double)(m_pvTempo) * (fRatio+1.0) +.5);
  169.         //tw.spr("GBS: %d(%d) -> %d\r", iBeatNum, pvOldTempo, m_pvTempo);
  170.     }
  171.  
  172.     int iBeatNum = iCurrBeatNum - m_iLastBeatNum;
  173.     if (m_iLastIndexPlayed != -1)
  174.         iBeatNum += GetBeatNum(m_iLastIndexPlayed);
  175.     assert(iBeatNum >= 0);
  176.     double ret = (double)(iBeatNum) / (double)(GetBeatNum(m_iNumNotes-1));
  177.  
  178.     // Return speed to normal.
  179.     if (bCadence)
  180.         m_pvTempo = pvOldTempo;
  181.     
  182.     return ret;
  183. }
  184.     
  185. public boolean bLastNote (int iCurrBeatNum, CRthmMods prmods/*=0*/)
  186. {    return m_iLastIndexPlayed >= m_iNumNotes-2; }
  187.     
  188.     public void SetTempo (char pvTempo)
  189.     { m_pvTempo = pvTempo;    }
  190.     public char pvGetTempo () { return m_pvTempo; }
  191.  
  192.     public char pvDensity () { return m_pvDensity; }
  193.     public char pvLength () { return m_pvLength; }
  194.     public int iNormalLength() { return GetBeatNum(m_iNumNotes-1); }
  195.     public char pvConsistency () { return m_pvConsistency; }
  196.     public int iAveDuration () {
  197.         int ret = GetBeatNum(m_iNumNotes-1)/m_iNumNotes;
  198.         if (ret!=0) return ret; else return 1;
  199.     }
  200.     
  201. // Construction/Destruction
  202.     public CRhythm ()
  203.     {    m_iLastBeatNum=-1; m_iLastIndexPlayed=-1;
  204.         m_pvTempo=1; m_iNumNotes=0; m_iNumAllocated=0;
  205.         m_arriNoteBeatNums=null; m_arrbstNoteStresses=null;
  206.         m_pvDensity=64; m_pvLength=64; m_pvConsistency=64;
  207.     }
  208.     //CRhythm (char* szInput);
  209.     
  210.     //int bSet (const char* szInput);
  211. public boolean bSet (CRhythm rthm)
  212. {
  213.     m_iLastBeatNum = rthm.m_iLastBeatNum;
  214.     m_iLastIndexPlayed = rthm.m_iLastIndexPlayed;
  215.     m_pvTempo = rthm.m_pvTempo;
  216.     m_iNumNotes = rthm.m_iNumNotes;
  217.     m_iNumAllocated = m_iNumNotes;
  218.     m_arriNoteBeatNums = new int[m_iNumAllocated];
  219.     m_arrbstNoteStresses = new int[m_iNumAllocated];
  220.     for (int C=0; C<m_iNumNotes; C++)
  221.     {    m_arriNoteBeatNums[C] = rthm.m_arriNoteBeatNums[C];
  222.         m_arrbstNoteStresses[C] = rthm.m_arrbstNoteStresses[C];
  223.     }
  224.     return true;
  225. }
  226.  
  227. public boolean bGenerate (char pvDensity/*=0*/, char pvLength/*=0*/,
  228.         char pvConsistency/*=0*/)
  229. {    // Re-initializing:
  230.     m_iLastIndexPlayed = -1;
  231.     
  232.     if (pvDensity!=0) m_pvDensity = pvDensity;
  233.     if (pvLength!=0) m_pvLength = pvLength;
  234.     if (pvConsistency!=0) m_pvConsistency = pvConsistency;
  235.  
  236.     double fNumSlots = (double)((int)m_pvLength);
  237.     assert(.0 <= fNumSlots && fNumSlots < 128.0);
  238.     fNumSlots = fMIN_NUMSLOTS + (fMAX_NUMSLOTS-fMIN_NUMSLOTS) *
  239.         fNumSlots / 127.0;
  240.         
  241.     double fDensity = (double)((int)m_pvDensity);
  242.     assert(.0 <= fDensity && fDensity < 128.0);
  243.     fDensity = fMIN_DENSITY + (fMAX_DENSITY-fMIN_DENSITY) *
  244.         fDensity / 127.0;
  245.     
  246.     double fConsistency = (double)((int)m_pvConsistency);
  247.     assert(.0 <= fConsistency && fConsistency < 128.0);
  248.     fConsistency = fMIN_CONSISTENCY +
  249.         (fMAX_CONSISTENCY-fMIN_CONSISTENCY) * fConsistency/127.0;
  250.     
  251.     m_iNumNotes = 0;
  252.     //double fAveInterval = 1.0/fDensity;
  253.     int iMaxNum = (int)(fNumSlots*fDensity + .5);
  254.     int iLastSlot = 1;
  255.     double fAveInterval = 1.0/fDensity;
  256.     double fCurrInterval = fAveInterval;
  257.     
  258.     AppendNote(iLastSlot, BST_MEDIUM);
  259.     for (int C=1; C<iMaxNum; C++)
  260.     {    if ((double)(rand()%100)/100.0 > fConsistency) { // Change interval...
  261.             double fRand = (double)(rand()%200)/100.0 - 1.0;
  262.             fCurrInterval = fRand*fAveInterval + fAveInterval;
  263.             if (fCurrInterval < 1.0) fCurrInterval = 1.0;
  264.         }
  265.         iLastSlot += (int)(.5 + fCurrInterval);
  266.         
  267.         int iLowBound = (int)(.5 + (1.0-fConsistency)*33.0);
  268.         int iHighBound = (int)(fConsistency*33.0 + 67.5);
  269.         int iRand = rand()%100;    // 0 to 99
  270.         int bst;
  271.         if (iRand < iLowBound) bst = BST_LIGHT;
  272.         else
  273.         {    if (iRand < iHighBound) bst = BST_MEDIUM;
  274.             else bst = BST_HEAVY;
  275.         }
  276.         AppendNote(iLastSlot, bst);
  277.     }
  278.     // Mark end with whisper (altho the BST doesn't matter);
  279.     AppendNote((int)(m_arriNoteBeatNums[iMaxNum-1] + fCurrInterval -1.0+.5),
  280.         BST_WHISPER);
  281.     return true;
  282. }
  283. // Implementation
  284. int bstGetNormalStatus (int iBeatNum, int piDuration)
  285. {
  286.     if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  287.         return BST_NO_NOTE;
  288.     if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
  289.         m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
  290.         if (m_iLastIndexPlayed != -1)
  291.             m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
  292.         m_iLastIndexPlayed++;
  293.         if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  294.             return BST_NO_NOTE;    // Last note is just a marker.
  295.         // Calculate duration:
  296.         bogus_piDuration = (int)((GetBeatNum(m_iLastIndexPlayed+1) -
  297.             GetBeatNum(m_iLastIndexPlayed))*1.1);
  298.         // Last note plays until next line's 1st note:
  299.         if (m_iLastIndexPlayed == m_iNumNotes - 2)
  300.             bogus_piDuration += GetBeatNum(0) * 1.1;
  301.  
  302.         return m_arrbstNoteStresses[m_iLastIndexPlayed];
  303.     }
  304.     return BST_NO_NOTE;
  305. }
  306.  
  307. int bstGetConstantStatus (int iBeatNum, double fArg,
  308.         int piDuration)
  309. {
  310.     if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  311.         return BST_NO_NOTE;
  312.     if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
  313.         // Update this as if we were normally playing.
  314.         m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
  315.         if (m_iLastIndexPlayed != -1)
  316.             m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
  317.         m_iLastIndexPlayed++;
  318.         if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  319.             return BST_NO_NOTE;    // End: Last note is just a marker.
  320.     }
  321.     int iIntervalLen = (int)(.5 + fArg*m_pvTempo);
  322.     if (iBeatNum % iIntervalLen == 0)
  323.     {    bogus_piDuration = (int)(1.1 * iIntervalLen);
  324.         if (iBeatNum % (iIntervalLen*2) == 0 && mod(rand(),4) == 0)
  325.             return BST_MEDIUM;
  326.         return BST_LIGHT;
  327.     }
  328.     return BST_NO_NOTE;
  329. }
  330.  
  331. int bstGetBetweenStatus (int iBeatNum, double fArg,
  332.         int piDuration)
  333. {
  334.     if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  335.         return BST_NO_NOTE;
  336.     if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
  337.         // Update this as if we were normally playing.
  338.         m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
  339.         if (m_iLastIndexPlayed != -1)
  340.             m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
  341.         m_iLastIndexPlayed++;
  342.         if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  343.             return BST_NO_NOTE;    // End: Last note is just a marker.
  344.     }
  345.     int iPrevBeat;
  346.     if (m_iLastIndexPlayed == -1)
  347.         iPrevBeat = 0;
  348.     else iPrevBeat = GetBeatNum(m_iLastIndexPlayed);
  349.     int iNextBeat = GetBeatNum(m_iLastIndexPlayed+1);
  350.     int iDist = (int)(.5 + (double)(iNextBeat - iPrevBeat) * fArg);
  351.     if (iPrevBeat + iDist == iBeatNum) {
  352.         bogus_piDuration = (int)(1.1 * (iNextBeat - iPrevBeat));
  353.         return BST_LIGHT;
  354.     }
  355.     return BST_NO_NOTE;
  356. }
  357.  
  358. int bstGetPeriodicStatus (int iBeatNum, double fArg,
  359.         int piDuration)
  360. {
  361.     if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  362.         return BST_NO_NOTE;
  363.     if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
  364.         // Update this as if we were normally playing.
  365.         m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
  366.         if (m_iLastIndexPlayed != -1)
  367.             m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
  368.         m_iLastIndexPlayed++;
  369.         if (m_iLastIndexPlayed >= m_iNumNotes - 1)
  370.             return BST_NO_NOTE;    // End: Last note is just a marker.
  371.     }
  372.     if (iBeatNum % m_pvTempo != 0)
  373.         return BST_NO_NOTE;
  374.     iBeatNum /= m_pvTempo;    // Switch to internal time units.
  375.     int iPeriodLen = (int)(.5 + fArg);
  376.     // Which beat in the subrhythm am I on?
  377.     iBeatNum = mod(iBeatNum, iPeriodLen);
  378.     // Depends on m_pvDensity, m_pvConsistency, iBeatNum.
  379.     double fDensity = (double)((int)m_pvDensity);
  380.     fDensity = /*fMIN_DENSITY +*/ (fMAX_DENSITY-fMIN_DENSITY) *
  381.         fDensity / 127.0;
  382.     double fConsistency = (double)((int)m_pvConsistency);
  383.     fConsistency = fConsistency/127.0;
  384.     int iAveInterval = (int)(.5 + 1.0/fDensity);
  385.     // Hash depends fully on iBeatNum/iAveInterval
  386.     double fHash = (iBeatNum/iAveInterval) ^
  387.         (m_pvConsistency<<2) ^ m_pvLength ^ (m_pvDensity<<3);
  388.     // A number between 0 and iPeriodLen - 1...
  389.     fHash = (1.0 - fConsistency) * (double)((int)(fHash) % iAveInterval);
  390.     if (iBeatNum % iAveInterval == (int)(fHash+.5)) {
  391.         bogus_piDuration = (int)((double)(iAveInterval) * 1.1) * m_pvTempo;
  392.         //TRACE("(+%d,%d,%.1f)", iBeatNum, iAveInterval, fHash);
  393.         return BST_LIGHT;
  394.     }
  395.     //TRACE("_-%d,%d,%.1f_", iBeatNum, iAveInterval, fHash);
  396.     return BST_NO_NOTE;
  397. }
  398.  
  399. void AppendNote (int iBeatNum, int bst)
  400. {    assert(bst != BST_NO_NOTE);
  401.     assert(iBeatNum > 0);
  402.     assert (0 <= m_iNumNotes ||
  403.         m_arriNoteBeatNums[m_iNumNotes-1] <= iBeatNum);
  404.         
  405.     if (m_iNumNotes == m_iNumAllocated)
  406.     {
  407.         m_iNumAllocated += 10;
  408.         int[] temp = m_arriNoteBeatNums;
  409.         m_arriNoteBeatNums = new int[m_iNumAllocated];
  410.         for (int C=0; C<m_iNumAllocated-10; C++)
  411.             m_arriNoteBeatNums[C] = temp[C];
  412.         temp = m_arrbstNoteStresses;
  413.         m_arrbstNoteStresses = new int[m_iNumAllocated];
  414.         for (int C=0; C<m_iNumAllocated-10; C++)
  415.             m_arrbstNoteStresses[C] = temp[C];
  416.     }
  417.     m_iNumNotes++;
  418.     assert(m_iNumNotes <= m_iNumAllocated);
  419.     m_arriNoteBeatNums[m_iNumNotes-1] = iBeatNum;
  420.     m_arrbstNoteStresses[m_iNumNotes-1] = bst;
  421. }
  422.     
  423.     // Given the index of a note in the rhythm, return the number
  424.     // of beats it occurs after the start, based on the current
  425.     // tempo.
  426.     int GetBeatNum (int iNoteIndex)
  427.     {    assert(iNoteIndex < m_iNumNotes);
  428.         return m_arriNoteBeatNums[iNoteIndex] * (int)(m_pvTempo); }
  429. }
  430.  
  431. //----------------------------------------------------------
  432.