private float getBestPitch(float[] audioFloatBuffer) { if (PITCHDETECTOR.equals("YIN")) { float yin_pitch = yin.getPitch(audioFloatBuffer); // Pitch pitchYIN= // Pitch.getInstance(PitchUnit.HERTZ,(double)yin_pitch); // int midiKeyYIN = (int)pitchYIN.getPitch(PitchUnit.MIDI_KEY); // float yin_prob = yin.getProbability(); yin_cnt++; pitch_probability = yin.getProbability(); return yin_pitch; } else if (PITCHDETECTOR.equals("MPM")) { float mpm_pitch = mpm.getPitch(audioFloatBuffer); // Pitch pitchMPM= // Pitch.getInstance(PitchUnit.HERTZ,(double)mpm_pitch); // int midiKeyMPM = (int)pitchMPM.getPitch(PitchUnit.MIDI_KEY); // float mcleod_prob = mpm.getProbability(); pitch_probability = mpm.getProbability(); mpm_cnt++; return mpm_pitch; } else { System.err.println("SHIT: PITCHDETECTOR: " + PITCHDETECTOR); System.exit(-1); return -1; } // TODO "2 Ohren " ????? erstmal beide evaluieren // if(midiKeyYIN==midiKeyMPM) { // --> wird am HŠufigsten eintreten ! // yin_cnt++; // pitch_probability=yin_prob; // return yin_pitch; // } // else { // if(midiKeyYIN==lastDetectedMidiKey) {//dann nehme YIN pitch // yin_cnt++; // pitch_probability=yin_prob; // return yin_pitch; // } // else { // mpm_cnt++; // pitch_probability=mcleod_prob; // return mpm_pitch; // } // } }
/** * <b>This is the most important function of the collector pipeline</b> First we detect the pitch * of the audioFloatBuffer using YIN or MPM.<br> * Then the collector process starts, checking onsets and offsets based on midiKeys and dB, * collects<br> * and convert these pich vectors to abc-notes based on the bpm, samplerate buffersize and * bufferoverlap.<br> */ private void detectPitchAndCollect(float[] audioFloatBuffer, double level) { int midiKey; String note; // TODO pitchInHertz = getBestPitch(audioFloatBuffer); // ---------- ENTSCHEIDUNG ---------- // pitchInHertz=mpm_pitch; pitch = Pitch.getInstance(PitchUnit.HERTZ, (double) pitchInHertz); midiKey = (int) pitch.getPitch( PitchUnit.MIDI_KEY); // PitchConverter.hertzToMidiKey((double)pitchInHertz); if (model.plottingSelected()) { plotterYIN.setData(yin.getCurrentBuffer()); plotterYIN.setInfoString("CURRENT PITCH: " + pitchInHertz + "Hz PROB: " + pitch_probability); plotterMPM.setData(mpm.getCurrentBuffer()); plotterMPM.setInfoString("CURRENT PITCH: " + pitchInHertz + "Hz PROB: " + pitch_probability); plotterBUFFER.setData(audioFloatBuffer); plotterBUFFER.setInfoString("level: " + level); } // nach dem pitch erkannt wurde muss ggf. entsprechend dem Instrument // transponiert werden if (model.getTransposeRecIndex() == 1) { // Bb Clarinet: 2 halftonesteps up pitch.convertPitch(2); pitchInHertz = (float) pitch.getPitch(PitchUnit.HERTZ); midiKey = PitchConverter.hertzToMidiKey((double) pitchInHertz); } String[] arr = pitch.getBaseNote(pitchInHertz).split(" "); String note2 = arr[0]; int oktave = Integer.parseInt(arr[1]); // note = pitch.noteName(); String str = ""; // formatted Info output to GUI str = pitchInHertz == -1 ? "NO PITCH DETECTED" : note + " at " + String.format("%.5g%n", pitchInHertz) + "Hz - IDEAL: " + String.format("%.5g%n", pitch.getIdealFreq(note2, oktave)) + "Hz - PROB: " + String.format("%.5g%n", pitch_probability) + "%"; model.firePropertyChange(ControllerEngine.INFO_LABEL_PROPERTY, "", str); countMSprocessing += (audioFloatBuffer.length - overlap) / audioSampleRate * 1000.0f; float duration = (bufferSize - overlap) / audioSampleRate * 1000.0f; // finally: // collect(audioFloatBuffer, midiKey, duration, level, note); // ------------------------- begin collector process ------------------------- // ----- sammel ALLE erkannten Noten fuer statistiken ----- if (midiKeySammlerInsgesamt.get(midiKey) != null) { midiKeySammlerInsgesamt.put(midiKey, midiKeySammlerInsgesamt.get(midiKey) + duration); } else { midiKeySammlerInsgesamt.put(midiKey, duration); } // TODO level neuer Ansatz ? zusaetzliche offset/Onset bedingung // levels.add(level); // // boolean minima=true; // Vector<double[]>extremwerte = jAMUtils.detectExtremum(levels, delta, minima); // // //sysout // if(!model.isEvaluating() && extremwerte.size()==1) { //kann so immer nur 1 finden //// jAMUtils.printArray(levels); // String str=""; // for (int i = 0; i < extremwerte.size(); i++) { // str+= "(" + extremwerte.get(i)[0] + ","+extremwerte.get(i)[1] + "),"; // } // System.out.println("============> EXTREM!!!: " + str + " at levels: " + levels); // System.out.println("midiKey: " + midiKey); // // levels.clear(); //wenn ein minima entdeckt: offset und dann leeren ? // } /** * * wenn eine note zb 200ms lang, dann -> 16tel aber die 50 ms muessen beim NŠchsten Mal * ignoriert werden wenn dies pausen entspricht !!! sonst kann sein dass zB z(3) gemalt wird * obwohl z(2) !!! * * <p>if(msToIgnore>0 && !ONSET) { //MINIMUM_DURATION dur+=duration; if(dur<msToIgnore) return; * else { System.out.println( "============================================>>>>>> IGNORED: " + * dur + "ms OF DATA - msToIgnore: " + msToIgnore); dur=0; msToIgnore=0; } } */ boolean silence = jAMUtils.isSilence(audioFloatBuffer, MINIMUM_LEVEL); // 1. OFFSET basierend auf neuer note! if ((ONSET && midiKey > 0 && !silence /* level > MINIMUM_LEVEL*/) && (midiKey != lastTakenMidiKey)) { // es kommt ne andere /Note/ // System.out.println("POSSIBLE NEW NOTE: "+ midiKey); if (newNoteCount == 0) // die erste "andere" Note newNoteCount++; else if (midiKey == lastDetectedMidiKey) newNoteCount++; if (newNoteCount > (int) (MINIMUM_DURATION / duration)) { // 60/25.01 --> 2 also mind. 3 nehmen! wie sonst auch ONSET = false; // dann macht er jetzt unten ne Entscheidung und beim next Mal fŠngt er an die // neue note zu collecten NEW_NOTE_ONSET = true; // TODO sinn? newNoteCount = 0; // sysout if (!model.isEvaluating() && jAM.SYSOUT) System.out.println( timestamp() + " ================================================== OFFSET NEWNOTE: " + midiKey + " could be possible new note"); } // 2. ONSET } else if (!ONSET && midiKey > 0 && !silence /*&& level > MINIMUM_LEVEL*/) { newNoteCount = 0; // gibts diese note schon? und kam sie beim letzten Mal? if (midiKeySammler.get(midiKey) != null && midiKey == lastDetectedMidiKey) { midiKeySammler.put(midiKey, midiKeySammler.get(midiKey) + duration); if (midiKeySammler.get(midiKey) > MINIMUM_DURATION) { // // sysout if (!model.isEvaluating() && jAM.SYSOUT) System.out.println( timestamp() + " ================================================== ONSET - Entscheidung basiert auf: " + midiKeySammler); ONSET = true; // wir kšnnen davon ausgehen dass "note" die lastTakenNote // wird, da sie alle Bedingungen fuer ein note-OFFSET erfŸllt // Problem: es kann sein dass zb 3 buffer A1 kommen, das is // ne new note bedingung // der naechst kommt dann hier rein und is aber diesmal A3 // also lastTakenNote="A3" anstatt A1 ??? lastTakenMidiKey = midiKey; midiKeySammler.clear(); } } else { midiKeySammler.put(midiKey, duration); } // 3. OFFSET basierend auf Pause } else if (silence || midiKey == 0 /*|| level < MINIMUM_LEVEL*/) { // sonst ist alles ne Pause: kein pitch und auch // level < MIN_LEVEL /** * gibts diese Pause schon? und kam sie beim letzten Mal? ob sie beim letzten Mal kam is * unwichtig es mŸssen die Pausen gezŠhlt werden! BSP: 60,60,60,0,0,0,0,55,0,0,0, --> die 55 * MUSS mitgezaehlt werden ! ??? stimmt das? */ if (midiKeySammler.get(0) != null && lastDetectedMidiKey == 0) { midiKeySammler.put(0, midiKeySammler.get(0) + duration); if (midiKeySammler.get(0) > MINIMUM_DURATION) { if (ONSET) { if (!model.isEvaluating() && jAM.SYSOUT) System.out.println( timestamp() + " ================================================== OFFSET - Entscheidung basiert auf: " + midiKeySammler); ONSET = false; // jetzt ist wieder vorbei NEW_NOTE_ONSET = false; } midiKeySammler.clear(); } } else { midiKeySammler.put(0, duration); } } // ----- wenn nun ONSET==true anfangen zu sammeln bis ONSET==false! if (ONSET) { if (midiKeysRests.size() > 0 && !NEW_NOTE_ONSET) { // hier sind nun pausen in der off Phase gezaehlt worden detectRest(duration); } else { // sonst: sammle noten // hier midiKey und level speichern: midiKeysAndLevels.add(new Float[] {(float) midiKey, (float) level}); } } else { // wenn ein OFFSET und noten sind vorhanden: entscheidung! if (midiKeysAndLevels.size() > 0) { detectNote(duration); } else // sonst sammple pausen midiKeysRests.add(midiKey); } lastDetectedMidiKey = midiKey; // TODO fft // fft(audioFloatBuffer); // TODO sysout if (!model.isEvaluating() && jAM.SYSOUT) { if (pitchInHertz == -1) System.out.println( timestamp() + "\t" + "--> Rest: " + note + (note.length() == 2 ? "\t" : "") + "\t\t midiKey: " + midiKey + "\t RMS: " + String.format("%.2f", level) + " Zustand: " + (ONSET ? "ONSET " : "OFFSET ") + (silence ? "SILENCE" : "NO SILENCE")); else System.out.println( timestamp() + "\t" + "--> Note: " + note + (note.length() == 2 ? "\t" : "") + "\t midiKey: " + midiKey + "\t RMS: " + String.format("%.2f", level) + " Zustand: " + (ONSET ? "ONSET " : "OFFSET ") + (silence ? "SILENCE" : "NO SILENCE")); } }