//THIS GIVES A GRAPHICAL PICTURE OF THE RELATIVE PITCH VALUES OBTAINED BY //GENERATING THE JUST INTONATION MAJOR SCALE FREQUENCIES BY FOLLOWING THE //"PROGRESSION OF 5ths" i.e. TAKING THE 3RD HARMONIC. //NOTE TO MYSELF: HERE IS HOW TO CREATE THE .jar FILE (BUT I THINK IT IS UNNECESSARY) //jar cvf JIKeyChanges.jar JIKeyChanges.class Factors.class KeyArray.class import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.util.Vector; public class JIKeyChanges extends Applet implements ActionListener, Runnable { int kk = 0; String b1s = "Draw Scale Pitches from Asc/Desc 5ths"; Button b1 = new Button(b1s); Image bufferImage; Graphics bufferGraphics; Thread animatorThread; boolean animation_is_set_to_stop; boolean first_time_painting = true; int delay; final int X_LENGTH = 500; final int Y_LENGTH = 500; final int LEFT_MARGIN_LEN = 10; final int LEFT_MARGIN_XCOORD = LEFT_MARGIN_LEN; final int RIGHT_MARGIN_LEN = 10; final int RIGHT_MARGIN_XCOORD = X_LENGTH - RIGHT_MARGIN_LEN; final int TOP_MARGIN_LEN = 30; final int TOP_MARGIN_YCOORD = TOP_MARGIN_LEN; final int BOT_MARGIN_LEN = 80; final int BOT_MARGIN_YCOORD = Y_LENGTH - BOT_MARGIN_LEN; final int abscissaHeight = Y_LENGTH - BOT_MARGIN_LEN - 1; final double yScaleFactor =(double)(abscissaHeight-TOP_MARGIN_YCOORD)/(2.0-1.0); int j; final int numAxisDivisions = 24; final int xIncrement= X_LENGTH / numAxisDivisions; final int maxNumberOfSteps = 11; final int numberOfNotesInScale = 7; int[] x = new int[numAxisDivisions+1]; int[] yy = new int[numberOfNotesInScale]; double[] y = new double[numberOfNotesInScale]; KeyArray[] keyArray = new KeyArray[25]; String[] CNoteName = new String[numberOfNotesInScale]; String[] circleOf5thsKeys = new String[25]; String fmt = "0.00000"; java.text.DecimalFormat dFmt = new java.text.DecimalFormat(fmt); //--------------------------------------------------------------------------- public void init() { setLayout(new FlowLayout()); setBackground(Color.white); add(b1); b1.addActionListener(this); j = 0; //ANIMATION BUFFER bufferImage = createImage( X_LENGTH, Y_LENGTH ); bufferGraphics = bufferImage.getGraphics(); for( int i=0; i<=numAxisDivisions; i++ ) x[i] = LEFT_MARGIN_LEN + xIncrement * i; for( short i = 0; i <= 24; i++ ) keyArray[i] = new KeyArray(); CNoteName[0] = new String("C"); CNoteName[1] = new String("D"); CNoteName[2] = new String("E"); CNoteName[3] = new String("F"); CNoteName[4] = new String("G"); CNoteName[5] = new String("A"); CNoteName[6] = new String("B"); computeKeyChanges(); repaint(); animation_is_set_to_stop = true; //CODE FOR ANIMATION TIMING delay = 10; //8; //( fps > 0 ) ? (1000 / fps ) : 100; } //---------------------------------------------------------------------------- public void paint( Graphics g ) { g.setColor(Color.black); bufferGraphics.setColor( getBackground() ); bufferGraphics.fillRect( LEFT_MARGIN_XCOORD+2, TOP_MARGIN_YCOORD+2, X_LENGTH - LEFT_MARGIN_LEN - RIGHT_MARGIN_LEN -4, Y_LENGTH - BOT_MARGIN_LEN - TOP_MARGIN_LEN -4); bufferGraphics.setColor( Color.black); bufferGraphics.drawRect( LEFT_MARGIN_XCOORD, TOP_MARGIN_YCOORD, X_LENGTH - LEFT_MARGIN_LEN - RIGHT_MARGIN_LEN, Y_LENGTH - BOT_MARGIN_LEN - TOP_MARGIN_LEN -1 ); for( int i=0; i maxNumberOfSteps ) max = Math.min(maxNumberOfSteps, j ); if( j >= maxNumberOfSteps ) bufferGraphics.drawString( "The Tonic key is a different color", x[2], abscissaHeight + 40 ); for( int key = 1; key <= max; key++) { for( int i=0; i< numberOfNotesInScale; i++ ) { y[i] = yScaleFactor*(keyArray[12+key].y[i] - 1.0 ); yy[i] = abscissaHeight - (int)y[i]; if( i==0 ) { bufferGraphics.setColor( Color.orange); bufferGraphics.drawLine( x[12+key], yy[i]+1, x[12+key+1], yy[i]+1); } else bufferGraphics.setColor( Color.red); bufferGraphics.drawLine( x[12+key], yy[i], x[12+key+1], yy[i] ); bufferGraphics.drawLine( x[12+key], yy[i]-1, x[12+key+1], yy[i]-1); bufferGraphics.setColor( Color.black); bufferGraphics.drawString( keyArray[12+key].keyName, x[12+key]+2, Y_LENGTH - BOT_MARGIN_LEN + 18 ); } for( int i=0; i< numberOfNotesInScale; i++ ) { y[i] = yScaleFactor*(keyArray[12-key].y[i] - 1.0 ); yy[i] = abscissaHeight - (int)y[i]; if( i==0 ) { bufferGraphics.setColor( Color.green); bufferGraphics.drawLine( x[12-key], yy[i]+1, x[12-key+1], yy[i]+1); } else bufferGraphics.setColor( Color.blue); bufferGraphics.drawLine( x[12-key], yy[i], x[12-key+1], yy[i]); bufferGraphics.drawLine( x[12-key], yy[i]-1, x[12-key+1], yy[i]-1); bufferGraphics.setColor( Color.black); bufferGraphics.drawString( keyArray[12-key].keyName, x[12-key]+2, Y_LENGTH - BOT_MARGIN_LEN + 18 ); } } g.drawImage(bufferImage, 1, 1, null); //SHOW PLOT BUFFER } //-------------------------------------------------------------------------- public void update( Graphics g) //WE OVERRIDE update() TO AVOID CLEARING { //THE BACKGROUND UNNECESSARILY paint(g); } //-------------------------------------------------------------------------- public void run() { Thread.currentThread().setPriority( Thread.MIN_PRIORITY ); Thread currentThread = Thread.currentThread(); long startTime = System.currentTimeMillis(); while( currentThread == animatorThread && j <= maxNumberOfSteps ) { j++; repaint( LEFT_MARGIN_XCOORD, TOP_MARGIN_YCOORD, X_LENGTH - LEFT_MARGIN_LEN - RIGHT_MARGIN_LEN, Y_LENGTH - TOP_MARGIN_LEN ); try { startTime += delay; Thread.sleep( Math.max( 0, startTime-System.currentTimeMillis() )); } catch( InterruptedException e ) { break; } if( kk == 2 ) { animation_is_set_to_stop = true; stop(); } } } //-------------------------------------------------------------------------- public void start() { if( animation_is_set_to_stop ) { } else //START ANIMATING { if( animatorThread == null ) { animatorThread = new Thread( this ); } animatorThread.start(); //THIS STARTS run() ON ANIMATOR THREAD } } //-------------------------------------------------------------------------- public void stop() { animatorThread = null; } //-------------------------------------------------------------------------- public void actionPerformed( ActionEvent e ) { // BUTTONS String tst; tst = e.getActionCommand(); if( b1s.equals(tst) ) //RUN { animation_is_set_to_stop = false; kk = 0; } start(); } //--------------------------------------------------------------------------- public void computeKeyChanges( ) { int i; //THE PRIME FACTORIZED NUMERATORS // OF THE J ARRAY Factors[] Jnumer = new Factors[numberOfNotesInScale]; Factors[] Jn2 = new Factors[numberOfNotesInScale]; for( i=0; i= 2 ) Jdenom[i].appendFactor( 2 ); //REDUCE FRACTIONS for( int j=0; j < Jdenom[i].numberOfFactors; j++ ) { for( int k=0; k < Jnumer[i].numberOfFactors; k++ ) { if( Jdenom[i].primeFactors[j] != 1 ) { if( Jdenom[i].primeFactors[j] == Jnumer[i].primeFactors[k] ) { Jdenom[i].primeFactors[j] = 1; Jnumer[i].primeFactors[k] = 1; break; } } } } } /* String output1 = ""; for( i=0; i < numberOfNotesInScale; i++ ) { output1 = output1 + Jnumer[i].multiply() + "/" + Jdenom[i].multiply() + " "; } System.out.println( output1 ); */ for( i=0; i < numberOfNotesInScale; i++ ) { keyArray[keychanges].y[i] = (double)Jnumer[i].multiply()/(double)Jdenom[i].multiply(); keyArray[keychanges].keyName = circleOf5thsKeys[keychanges]; } } //-----------------NOW FOR FLATS: ASCEND BY SCALE 4ths ( = DESCEND BY 5ths ) opNum = 2; //4=2*2 SO APPEND IT TWICE!; opDen = 3; for( int keychanges = 11; keychanges >=1; keychanges-- ) { for( i=0; i < numberOfNotesInScale; i++ ) { Jn2[i].appendFactor( opNum ); Jn2[i].appendFactor( opNum ); Jd2[i].appendFactor( opDen ); //System.out.println( ); } for( i=0; i < numberOfNotesInScale; i++ ) //BRING DOWN INTO OUR OCTAVE { while( Jn2[i].multiply() / Jd2[i].multiply() >= 2 ) Jd2[i].appendFactor( 2 ); //REDUCE FRACTIONS for( int j=0; j < Jd2[i].numberOfFactors; j++ ) { for( int k=0; k < Jn2[i].numberOfFactors; k++ ) { if( Jd2[i].primeFactors[j] != 1 ) { if( Jd2[i].primeFactors[j] == Jn2[i].primeFactors[k] ) { Jd2[i].primeFactors[j] = 1; Jn2[i].primeFactors[k] = 1; break; } } } } } /* String output1 = ""; for( i=0; i < numberOfNotesInScale; i++ ) { output1 = output1 + Jn2[i].multiply() + "/" + Jd2[i].multiply() + " "; } System.out.println( output1 ); */ for( i=0; i < numberOfNotesInScale; i++ ) { keyArray[keychanges].y[i] = (double)Jn2[i].multiply()/(double)Jd2[i].multiply(); keyArray[keychanges].keyName = circleOf5thsKeys[keychanges]; } } } } //============================================================================== class Factors extends Object implements Cloneable { public final short numberOfFactors = 35; public int[] primeFactors = new int[numberOfFactors]; public Factors() { for( short i=0; i