/* UD Music Theory Test JApplet */ import java.applet.Applet; import java.awt.*; import java.awt.event.*; import javax.sound.midi.*; import java.io.*; import java.util.*; import java.net.*; public class UdmtMajorScaleTest extends Applet implements ActionListener, Runnable { private Button setupButton, playButton, stopButton; private Label midiInComboLabel, midiOutComboLabel, answerLabel; private Choice imntCombo; private UdmtMidiOutQueue myUdmtMidiOutQueue; private UdmtPianoDisplay myUdmtPianoDisplay; private int prevQptr = -1; private int numEventsRecorded = 0; // These note names are presented to the user as the major scales to be played private String[] NoteNames = {"C","C#","D","Eb","E","F","F#","G","Ab","A","Bb","B"}; // This array determines how each of the above major scales is spelled: sharps or flats. // "7" is used to get the correct enharmonics for C# major (7 sharps) // "6" is used to get the correct enharmonics for F# major (6 sharps) private String[] ScaleType = {"S","7" ,"S","F" ,"S","F","6", "S","F", "S","F", "S"}; // These 2 arrays are used to print the notes the user plays based on // whether the requested scale is spelled with sharps or flats private String[] SharpNames = {"C ","C#","D ","D#","E ","F ","F#","G ","G#","A ","A#","B "}; private String[] CSharpMajNames = {"B#","C#","D ","D#","E ","E#","F#","G ","G#","A ","A#","B "}; private String[] FSharpMajNames = {"C ","C#","D ","D#","E ","E#","F#","G ","G#","A ","A#","B "}; private String[] FlatNames = {"C ","Db","D ","Eb","E ","F ","Gb","G ","Ab","A ","Bb","B "}; private String[] audioScales = {"cmaj.au","csmaj.au","dmaj.au","ebmaj.au", "emaj.au","fmaj.au","fsmaj.au","gmaj.au","abmaj.au","amaj.au","bbmaj.au","bmaj.au"}; private String audioVerify = "verifymidi.au"; private String[] audioCorrect = {"excellent.au","groovy.au","yougotit.au","doingreat.au","gimmemore.au"}; private String[] audioIncorrect = {"ut-oh.au","watchthatnote.au","whoops.au","didyouhearthat.au","whatwasthat.au"}; private String audioTryAgain = "playitagain.au"; private String audioCompleted = "completed.au"; private String audioPassed = "passed.au"; private String audioFailed = "failed.au"; final int middlec = 60; private String userStatus = "READY"; private boolean userFirstGuess = false; private int[] userTestQuestions; private int userTestPhase, currentTestQuestion, currentScaleNote, currentUserErrors; private String userNotes = ""; private Rectangle rect; private Thread looper; private boolean running; private long runSeconds = 0; private int runCount; //--------------------------------------------------------------------------------------------- private int[][] noteVels; private int scalenum; private int[] MajorScale = { 0, 2, 4, 5, 7, 9, 11, 12 }; private int userNumCorrect = 0, userNumQues = 0, userPercent = 0; final int passingGrade = 65; private String[] audioQueue; private int[] audioDelays; private int audioQHead = 0; private int audioQTail = 0; private int audioWaitTime = 0; final int audioQueueLength = 100; //--------------------------------------------------------------------------------------------- public void init() { myUdmtMidiOutQueue = new UdmtMidiOutQueue(); //Container content = getContentPane(); //content.setLayout(new BorderLayout()); Panel msgPanel = new Panel(); msgPanel.setLayout (new FlowLayout() ); msgPanel.add(new Label("Midi In Device : "+ myUdmtMidiOutQueue.getCurrMidiInDeviceName())); msgPanel.add(new Label(" ")); msgPanel.add(new Label("Midi Out Device : "+ myUdmtMidiOutQueue.getCurrMidiOutDeviceName())); msgPanel.add(new Label(" ")); setupButton = new Button("MIDI Setup"); setupButton.addActionListener(this); setupButton.setEnabled(false); msgPanel.add(setupButton); //imntCombo = new Choice(); //for (int ix=0; ix= MajorScale.length) { userTestPhase = 3; } } else { currentUserErrors++; queueAudio( pickAudio(audioIncorrect) , 1); } } phaseProcessing(); } //--------------------------------------------------------------------------------------------- private void phaseProcessing() { if (userTestPhase == 1) { //System.out.println("Phase 1"); currentTestQuestion = 0; currentScaleNote = 0; currentUserErrors = 0; userNumCorrect = 0; userNumQues = 0; userPercent = 0; askQuestion(); userTestPhase = 2; } else if (userTestPhase == 2) { //System.out.println("Phase 2"); } else if (userTestPhase == 3) { //System.out.println("Phase 3"); if (userFirstGuess) { userNumQues++; } if (currentUserErrors == 0) { queueAudio(pickAudio(audioCorrect), 2); if (userFirstGuess) { userNumCorrect++; } currentTestQuestion++; if (currentTestQuestion >= userTestQuestions.length) { // User completed all questions on the test. showUserScore(); if (userPercent == 100) { queueAudio(audioCompleted, 3); myUdmtPianoDisplay.setBanner("CONGRATULATIONS!!! You completed this unit."); } else if (userPercent >= passingGrade) { queueAudio(audioPassed, 4); myUdmtPianoDisplay.setBanner("Test Complete. You passed, but will need to retake this test before you can move on to the next unit."); } else { queueAudio(audioFailed, 4); myUdmtPianoDisplay.setBanner("Test Complete. I'm sorry, but you failed this test and will need to review the lesson and retake it at a later date."); } playButton.setLabel("Begin Test"); userTestPhase = 0; } else { currentScaleNote = 0; currentUserErrors = 0; askQuestion(); userTestPhase = 2; } } else { queueAudio(audioTryAgain, 1); userFirstGuess = false; currentScaleNote = 0; currentUserErrors = 0; userNotes = ""; myUdmtPianoDisplay.setUserNotesPlayedCorrectly(""); userTestPhase = 2; } } } //--------------------------------------------------------------------------------------------- private void askQuestion() { scalenum = userTestQuestions[currentTestQuestion]; userFirstGuess = true; myUdmtPianoDisplay.setBanner("Please play a " + NoteNames[scalenum] + " Major scale (one octave, ascending). If you hit a wrong note, replay the correct note."); queueAudio(audioScales[scalenum], 2); showUserScore(); userNotes = ""; myUdmtPianoDisplay.setUserNotesPlayedCorrectly(""); } //--------------------------------------------------------------------------------------------- private void showUserScore() { String score; if (userNumQues == 0) { userPercent = 0; score = userNumCorrect + " / " + userNumQues + " = " + userPercent + "%"; } else { userPercent = (int)(userNumCorrect * 100 / userNumQues); score = userNumCorrect + " / " + userNumQues + " = " + userPercent + "%"; } myUdmtPianoDisplay.setUserTestScore("Your score: " + score); } //--------------------------------------------------------------------------------------------- private void viewMidiInQueue() { int currQptr, maxQptr; long t; int c,n,v; //System.out.println("viewMidiInQueue"); maxQptr = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueueSize(); //System.out.println("Queue Size="+maxQptr); currQptr = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueuePtr(); //System.out.println("Prev Qptr ="+prevQptr+" Curr Qptr="+currQptr); if (currQptr == prevQptr) { //System.out.println("No new events recorded since you last checked"); } else { while (prevQptr != currQptr) { prevQptr++; if (prevQptr >= maxQptr) { prevQptr = 0; } t = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueueTime(prevQptr); c = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueueChnl(prevQptr); n = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueueNote(prevQptr); v = myUdmtMidiOutQueue.myMidiInReceiver.getMidiInQueueVel(prevQptr); //System.out.println("T="+t+" C="+c+" N="+n+" V="+v); numEventsRecorded++; //myUdmtPianoDisplay.setBanner("Number of Events Recorded from MIDI IN: "+numEventsRecorded); if (v > 0) // note on event was found in queue with velocity > 0 { checkScaleNote(n); } //keep track of all notes that are down now - this is used for the piano display noteVels[c][n] = v; } } } //--------------------------------------------------------------------------------------------- // Animation routines: //--------------------------------------------------------------------------------------------- public void start() { if(!running) { running = true; looper = new Thread(this); looper.start(); } } public void stop() { running = false; } public void run() { try { while(running) { repaint(); looper.sleep(50); frameNext(); } } catch(InterruptedException e) { running = false; } } public void update(Graphics g) { if(running) { if(rect == null) { rect = getBounds(); frameFirst(); } myUdmtPianoDisplay.paint(g); } } private void frameFirst() { myUdmtPianoDisplay.setBanner("Please verify that your MIDI Input is working correctly by playing notes on your piano keyboard and watching the display below."); queueAudio(audioVerify, 3); } //--------------------------------------------------------------------------------------------- private void frameNext() { viewMidiInQueue(); runCount++; if (audioWaitTime == 0) { if (audioQHead != audioQTail) { audioQTail++; if (audioQTail == audioQueue.length) { audioQTail = 0; } play(getCodeBase(), audioQueue[audioQTail]); audioWaitTime = audioDelays[audioQTail]; } // if } if (runCount >= 20) { runSeconds++; runCount = 0; // process audio queue if (audioWaitTime > 0) { audioWaitTime--; } } // if } // frameNext //--------------------------------------------------------------------------------------------- private void queueAudio(String audioFileName, int seconds) { audioQHead++; if (audioQHead == audioQueue.length) { audioQHead = 0; } if (audioQHead == audioQTail) // queue full - ignore new message { System.out.println("queueAudio: Audio Queue Is Full"); System.out.println("queueAudio: audioFileName = "+audioFileName); audioQHead--; // remove item from queue if queue is full if (audioQHead < 0) { audioQHead = audioQueue.length - 1; } } audioQueue[audioQHead] = audioFileName; audioDelays[audioQHead] = seconds; } //--------------------------------------------------------------------------------------------- private String pickAudio (String[] audioArray) { return( audioArray [ (int)(Math.random() * audioArray.length) ] ); } //--------------------------------------------------------------------------------------------- class UdmtPianoDisplay extends Panel { private String banner = " "; private String userTestScore = " "; private String userNotesPlayedCorrectly = " "; public UdmtPianoDisplay() { } public void setBanner(String newbanner) { banner = newbanner; } public void setUserTestScore(String newscore) { userTestScore = newscore; } public void setUserNotesPlayedCorrectly(String notelist) { userNotesPlayedCorrectly = notelist; } public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(30,80,740,100); g.setColor(Color.black); g.drawString(userTestScore,50,120); g.drawString(userNotesPlayedCorrectly,50,140); g.drawString(banner,50,160); for (int n=21; n<=108; n++) { g.setColor(Color.white); for (int c=0; c<16; c++) { if (noteVels[c][n] != 0) { g.setColor(Color.red); } } g.fillRect( (n-21)*8+50, 200, 7, 70 ); } } //--------------------------------------------------------------------------------------------- } // END OF CLASS UdmtPianoDisplay //--------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------- } // END OF CLASS UdmtMajorScaleTest //---------------------------------------------------------------------------------------------