home *** CD-ROM | disk | FTP | other *** search
Java Source | 2017-09-21 | 14.1 KB | 432 lines |
- /*typedef enum
- {
- final int RYMOD_CONSTANT=0;
- final int RYMOD_BETWEEN=1;
- final int RYMOD_PERIODIC=2;
- final int RYMOD_NONE=3;
- final int NUM_RYMODS=4;
- } RthmModify; // Hungarian: rymod
- */
-
- //----------------------------------------------------------
- import java.applet.Applet;
-
- class CRhythm extends Applet // Hungarian: rthm
- {
- int bogus_piDuration; // Bogus return value.
-
- // constants
- final int RYMOD_CONSTANT=0;
- final int RYMOD_BETWEEN=1;
- final int RYMOD_PERIODIC=2;
- final int RYMOD_NONE=3;
- final int NUM_RYMODS=4;
- 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 double fMIN_NUMSLOTS =6.0;
- final double fMAX_NUMSLOTS =64.0;
- final double fMIN_DENSITY =.1;
- final double fMAX_DENSITY =1.0;
- final double fMIN_CONSISTENCY =.3;
- final double fMAX_CONSISTENCY =1.0;
- // Members
- int m_iLastBeatNum; // When was the last time we were played?
- int m_iLastIndexPlayed; // What was the last note we returned?
- char m_pvTempo; // This name is actually misleading.
- // The larger this value is, the slower we go. See
- // GetBeatNum and bstGetConstantStatus.
-
- int m_iNumNotes; // Number of notes actually played in an
- // occurence of this rhythm/meter.
- int m_iNumAllocated;
- int m_arriNoteBeatNums[]; // Array of beat numbers: one for
- // each of the notes to play, where m_arriNoteBeatNums[2]=3
- // means the 2nd note will be played on the (3*m_pvTempo)'th
- // beat of the rhythm.
- // Assume beat numbers are in ascending order.
- int m_arrbstNoteStresses[]; // Array of stresses: one
- // for each of the notes to play.
-
- // The following chars are used for generating new rhythms.
- // None of these values specifically refer to a number, instead
- // they map into the range of allowable values. 0 for minimum,
- // 127 for max, 63-64 in the middle.
- char m_pvDensity; // What ratio of slots to fill.
- char m_pvLength; // How many slots to have available.
- // Directly proportional to periodicity.
- char m_pvConsistency; // Amount of repetition.
-
- //===============================================
- 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_arrbstNoteStresses[-1] = 0; }
- public int rand() { return (int)(Math.random() * 9747); }
-
- // Operations
- // Set when this occurence of the rhythm/meter will begin.
- void SetFirstBeat (int iBeatNum)
- { m_iLastBeatNum = iBeatNum; m_iLastIndexPlayed = -1; }
-
- int bstGetBeatStatus (int iCurrBeatNum,
- CRthmMods prmods, int piDuration)
- { bogus_piDuration = 0;
- assert(m_iNumNotes > 0);
- // For cadence, slowly become twice as slow by end of rhythm
- // (for now).
- char pvOldTempo = 0;
- boolean bCadence = /*prmods &&*/ prmods.bCadence;
- if (bCadence)
- { pvOldTempo = m_pvTempo;
- double fRatio = ((double)m_iLastIndexPlayed+1)/
- ((double)m_iNumNotes);
- if (fRatio < .0) fRatio = .0;
- else if (fRatio > 1.0) fRatio = 1.0;
- m_pvTempo = (char)(((double)m_pvTempo) * (fRatio+1.0) + .5);
- //tw.spr("GBS: %d(%d) -> %d\r", iBeatNum, pvOldTempo, m_pvTempo);
- }
- int iBeatNum = iCurrBeatNum - m_iLastBeatNum;
- if (m_iLastIndexPlayed != -1)
- iBeatNum += GetBeatNum(m_iLastIndexPlayed);
- assert(iBeatNum >= 0);
-
- int ret = -1;
- switch (prmods.rymod)
- { case RYMOD_CONSTANT:
- ret = bstGetConstantStatus(iBeatNum, prmods.fRMArg, piDuration);
- break;
- case RYMOD_BETWEEN:
- ret = bstGetBetweenStatus(iBeatNum, prmods.fRMArg, piDuration);
- break;
- case RYMOD_PERIODIC:
- ret = bstGetPeriodicStatus(iBeatNum, prmods.fRMArg, piDuration);
- break;
- case RYMOD_NONE:
- ret = bstGetNormalStatus(iBeatNum, piDuration);
- // How about a volume change for normal cadence?
- if (bCadence)
- { if (ret != BST_NO_NOTE && ret != BST_BANG)
- ret = (ret+1);
- }
- break;
- default: assert(false); break;
- }
-
- // Should we randomly insert a note where one shouldn't be?
- if (ret == BST_NO_NOTE && iBeatNum%m_pvTempo == 0) {
- double fRand = ((double)m_arriNoteBeatNums[m_iNumNotes-1] -
- m_arriNoteBeatNums[0]);
- fRand *= (double)(prmods.pvCoherence)*6.0/127.0;
- if (fRand < 1.0) fRand = 1.0;
- if (mod(rand(), (int)(fRand + .5)) == 0) {
- ret = BST_LIGHT;
- }
- }
-
- // Return speed to normal.
- if (bCadence)
- { m_pvTempo = pvOldTempo;
- }
-
- if (ret != BST_NO_NOTE && bogus_piDuration == 0)
- bogus_piDuration = m_pvTempo;
-
- return ret;
- }
-
- // Return -1 if the given beat number is before the current
- // iteration of the rhythm; 0 if it fits within; 1 if it
- // occurs after.
- public int iOutside (int iBeatNum, CRthmMods prmods/*=0*/)
- {
- double fPos = fPosition(iBeatNum, prmods);
- if (fPos <= 0) return -1;
- if (fPos <= 1) return 0;
- return 1;
- }
-
- public double fPosition (int iCurrBeatNum,
- CRthmMods prmods/*=0*/)
- {
- // For cadence, slowly become twice as slow by end of rhythm
- // (for now).
- assert(m_iNumNotes > 0);
- char pvOldTempo = 0;
- boolean bCadence = /*prmods && */prmods.bCadence;
- if (bCadence)
- { pvOldTempo = m_pvTempo;
- double fRatio = (double)(m_iLastIndexPlayed+1)/
- (double)(m_iNumNotes);
- if (fRatio < .0) fRatio = .0;
- else if (fRatio > 1.0) fRatio = 1.0;
- m_pvTempo = (char)((double)(m_pvTempo) * (fRatio+1.0) +.5);
- //tw.spr("GBS: %d(%d) -> %d\r", iBeatNum, pvOldTempo, m_pvTempo);
- }
-
- int iBeatNum = iCurrBeatNum - m_iLastBeatNum;
- if (m_iLastIndexPlayed != -1)
- iBeatNum += GetBeatNum(m_iLastIndexPlayed);
- assert(iBeatNum >= 0);
- double ret = (double)(iBeatNum) / (double)(GetBeatNum(m_iNumNotes-1));
-
- // Return speed to normal.
- if (bCadence)
- m_pvTempo = pvOldTempo;
-
- return ret;
- }
-
- public boolean bLastNote (int iCurrBeatNum, CRthmMods prmods/*=0*/)
- { return m_iLastIndexPlayed >= m_iNumNotes-2; }
-
- public void SetTempo (char pvTempo)
- { m_pvTempo = pvTempo; }
- public char pvGetTempo () { return m_pvTempo; }
-
- public char pvDensity () { return m_pvDensity; }
- public char pvLength () { return m_pvLength; }
- public int iNormalLength() { return GetBeatNum(m_iNumNotes-1); }
- public char pvConsistency () { return m_pvConsistency; }
- public int iAveDuration () {
- int ret = GetBeatNum(m_iNumNotes-1)/m_iNumNotes;
- if (ret!=0) return ret; else return 1;
- }
-
- // Construction/Destruction
- public CRhythm ()
- { m_iLastBeatNum=-1; m_iLastIndexPlayed=-1;
- m_pvTempo=1; m_iNumNotes=0; m_iNumAllocated=0;
- m_arriNoteBeatNums=null; m_arrbstNoteStresses=null;
- m_pvDensity=64; m_pvLength=64; m_pvConsistency=64;
- }
- //CRhythm (char* szInput);
-
- //int bSet (const char* szInput);
- public boolean bSet (CRhythm rthm)
- {
- m_iLastBeatNum = rthm.m_iLastBeatNum;
- m_iLastIndexPlayed = rthm.m_iLastIndexPlayed;
- m_pvTempo = rthm.m_pvTempo;
- m_iNumNotes = rthm.m_iNumNotes;
- m_iNumAllocated = m_iNumNotes;
- m_arriNoteBeatNums = new int[m_iNumAllocated];
- m_arrbstNoteStresses = new int[m_iNumAllocated];
- for (int C=0; C<m_iNumNotes; C++)
- { m_arriNoteBeatNums[C] = rthm.m_arriNoteBeatNums[C];
- m_arrbstNoteStresses[C] = rthm.m_arrbstNoteStresses[C];
- }
- return true;
- }
-
- public boolean bGenerate (char pvDensity/*=0*/, char pvLength/*=0*/,
- char pvConsistency/*=0*/)
- { // Re-initializing:
- m_iLastIndexPlayed = -1;
-
- if (pvDensity!=0) m_pvDensity = pvDensity;
- if (pvLength!=0) m_pvLength = pvLength;
- if (pvConsistency!=0) m_pvConsistency = pvConsistency;
-
- double fNumSlots = (double)((int)m_pvLength);
- assert(.0 <= fNumSlots && fNumSlots < 128.0);
- fNumSlots = fMIN_NUMSLOTS + (fMAX_NUMSLOTS-fMIN_NUMSLOTS) *
- fNumSlots / 127.0;
-
- double fDensity = (double)((int)m_pvDensity);
- assert(.0 <= fDensity && fDensity < 128.0);
- fDensity = fMIN_DENSITY + (fMAX_DENSITY-fMIN_DENSITY) *
- fDensity / 127.0;
-
- double fConsistency = (double)((int)m_pvConsistency);
- assert(.0 <= fConsistency && fConsistency < 128.0);
- fConsistency = fMIN_CONSISTENCY +
- (fMAX_CONSISTENCY-fMIN_CONSISTENCY) * fConsistency/127.0;
-
- m_iNumNotes = 0;
- //double fAveInterval = 1.0/fDensity;
- int iMaxNum = (int)(fNumSlots*fDensity + .5);
- int iLastSlot = 1;
- double fAveInterval = 1.0/fDensity;
- double fCurrInterval = fAveInterval;
-
- AppendNote(iLastSlot, BST_MEDIUM);
- for (int C=1; C<iMaxNum; C++)
- { if ((double)(rand()%100)/100.0 > fConsistency) { // Change interval...
- double fRand = (double)(rand()%200)/100.0 - 1.0;
- fCurrInterval = fRand*fAveInterval + fAveInterval;
- if (fCurrInterval < 1.0) fCurrInterval = 1.0;
- }
- iLastSlot += (int)(.5 + fCurrInterval);
-
- int iLowBound = (int)(.5 + (1.0-fConsistency)*33.0);
- int iHighBound = (int)(fConsistency*33.0 + 67.5);
- int iRand = rand()%100; // 0 to 99
- int bst;
- if (iRand < iLowBound) bst = BST_LIGHT;
- else
- { if (iRand < iHighBound) bst = BST_MEDIUM;
- else bst = BST_HEAVY;
- }
- AppendNote(iLastSlot, bst);
- }
- // Mark end with whisper (altho the BST doesn't matter);
- AppendNote((int)(m_arriNoteBeatNums[iMaxNum-1] + fCurrInterval -1.0+.5),
- BST_WHISPER);
- return true;
- }
- // Implementation
- int bstGetNormalStatus (int iBeatNum, int piDuration)
- {
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE;
- if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
- m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
- if (m_iLastIndexPlayed != -1)
- m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
- m_iLastIndexPlayed++;
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE; // Last note is just a marker.
- // Calculate duration:
- bogus_piDuration = (int)((GetBeatNum(m_iLastIndexPlayed+1) -
- GetBeatNum(m_iLastIndexPlayed))*1.1);
- // Last note plays until next line's 1st note:
- if (m_iLastIndexPlayed == m_iNumNotes - 2)
- bogus_piDuration += GetBeatNum(0) * 1.1;
-
- return m_arrbstNoteStresses[m_iLastIndexPlayed];
- }
- return BST_NO_NOTE;
- }
-
- int bstGetConstantStatus (int iBeatNum, double fArg,
- int piDuration)
- {
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE;
- if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
- // Update this as if we were normally playing.
- m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
- if (m_iLastIndexPlayed != -1)
- m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
- m_iLastIndexPlayed++;
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE; // End: Last note is just a marker.
- }
- int iIntervalLen = (int)(.5 + fArg*m_pvTempo);
- if (iBeatNum % iIntervalLen == 0)
- { bogus_piDuration = (int)(1.1 * iIntervalLen);
- if (iBeatNum % (iIntervalLen*2) == 0 && mod(rand(),4) == 0)
- return BST_MEDIUM;
- return BST_LIGHT;
- }
- return BST_NO_NOTE;
- }
-
- int bstGetBetweenStatus (int iBeatNum, double fArg,
- int piDuration)
- {
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE;
- if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
- // Update this as if we were normally playing.
- m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
- if (m_iLastIndexPlayed != -1)
- m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
- m_iLastIndexPlayed++;
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE; // End: Last note is just a marker.
- }
- int iPrevBeat;
- if (m_iLastIndexPlayed == -1)
- iPrevBeat = 0;
- else iPrevBeat = GetBeatNum(m_iLastIndexPlayed);
- int iNextBeat = GetBeatNum(m_iLastIndexPlayed+1);
- int iDist = (int)(.5 + (double)(iNextBeat - iPrevBeat) * fArg);
- if (iPrevBeat + iDist == iBeatNum) {
- bogus_piDuration = (int)(1.1 * (iNextBeat - iPrevBeat));
- return BST_LIGHT;
- }
- return BST_NO_NOTE;
- }
-
- int bstGetPeriodicStatus (int iBeatNum, double fArg,
- int piDuration)
- {
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE;
- if (GetBeatNum(m_iLastIndexPlayed+1) <= iBeatNum) {
- // Update this as if we were normally playing.
- m_iLastBeatNum = m_iLastBeatNum + iBeatNum;
- if (m_iLastIndexPlayed != -1)
- m_iLastBeatNum -= GetBeatNum(m_iLastIndexPlayed);
- m_iLastIndexPlayed++;
- if (m_iLastIndexPlayed >= m_iNumNotes - 1)
- return BST_NO_NOTE; // End: Last note is just a marker.
- }
- if (iBeatNum % m_pvTempo != 0)
- return BST_NO_NOTE;
- iBeatNum /= m_pvTempo; // Switch to internal time units.
- int iPeriodLen = (int)(.5 + fArg);
- // Which beat in the subrhythm am I on?
- iBeatNum = mod(iBeatNum, iPeriodLen);
- // Depends on m_pvDensity, m_pvConsistency, iBeatNum.
- double fDensity = (double)((int)m_pvDensity);
- fDensity = /*fMIN_DENSITY +*/ (fMAX_DENSITY-fMIN_DENSITY) *
- fDensity / 127.0;
- double fConsistency = (double)((int)m_pvConsistency);
- fConsistency = fConsistency/127.0;
- int iAveInterval = (int)(.5 + 1.0/fDensity);
- // Hash depends fully on iBeatNum/iAveInterval
- double fHash = (iBeatNum/iAveInterval) ^
- (m_pvConsistency<<2) ^ m_pvLength ^ (m_pvDensity<<3);
- // A number between 0 and iPeriodLen - 1...
- fHash = (1.0 - fConsistency) * (double)((int)(fHash) % iAveInterval);
- if (iBeatNum % iAveInterval == (int)(fHash+.5)) {
- bogus_piDuration = (int)((double)(iAveInterval) * 1.1) * m_pvTempo;
- //TRACE("(+%d,%d,%.1f)", iBeatNum, iAveInterval, fHash);
- return BST_LIGHT;
- }
- //TRACE("_-%d,%d,%.1f_", iBeatNum, iAveInterval, fHash);
- return BST_NO_NOTE;
- }
-
- void AppendNote (int iBeatNum, int bst)
- { assert(bst != BST_NO_NOTE);
- assert(iBeatNum > 0);
- assert (0 <= m_iNumNotes ||
- m_arriNoteBeatNums[m_iNumNotes-1] <= iBeatNum);
-
- if (m_iNumNotes == m_iNumAllocated)
- {
- m_iNumAllocated += 10;
- int[] temp = m_arriNoteBeatNums;
- m_arriNoteBeatNums = new int[m_iNumAllocated];
- for (int C=0; C<m_iNumAllocated-10; C++)
- m_arriNoteBeatNums[C] = temp[C];
- temp = m_arrbstNoteStresses;
- m_arrbstNoteStresses = new int[m_iNumAllocated];
- for (int C=0; C<m_iNumAllocated-10; C++)
- m_arrbstNoteStresses[C] = temp[C];
- }
- m_iNumNotes++;
- assert(m_iNumNotes <= m_iNumAllocated);
- m_arriNoteBeatNums[m_iNumNotes-1] = iBeatNum;
- m_arrbstNoteStresses[m_iNumNotes-1] = bst;
- }
-
- // Given the index of a note in the rhythm, return the number
- // of beats it occurs after the start, based on the current
- // tempo.
- int GetBeatNum (int iNoteIndex)
- { assert(iNoteIndex < m_iNumNotes);
- return m_arriNoteBeatNums[iNoteIndex] * (int)(m_pvTempo); }
- }
-
- //----------------------------------------------------------
-