00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package com.meapsoft;
00024
00025 import java.util.ArrayList;
00026
00027
00028
00029
00030
00031
00032
00033
00034 public class OnsetDetector implements FrameListener {
00035 STFT stft;
00036 long lastSeen;
00037 int histLen = 4, onsLen = 512;
00038 double[][] history;
00039 double[] onsets;
00040
00041 ArrayList listeners;
00042
00043
00044 double[] state;
00045
00046
00047
00048 double adaptation = 0.01;
00049
00050
00051
00052 double bandThresh = 2;
00053
00054
00055 double bandFrac = 0.3;
00056
00057 public OnsetDetector(STFT stft, double bandThresh, double bandFrac) {
00058 this.stft = stft;
00059 this.bandThresh = bandThresh;
00060 this.bandFrac = bandFrac;
00061
00062 this.listeners = new ArrayList();
00063 this.history = new double[histLen+1][];
00064 this.onsets = new double[onsLen];
00065
00066 state = new double[stft.getRows()];
00067 for(int i=0; i<state.length; i++)
00068 state[i] = 0.5/adaptation;
00069
00070 stft.addFrameListener(this);
00071 }
00072
00073 public void addOnsetListener(OnsetListener listener) {
00074 listeners.add(listener);
00075 }
00076 public void removeOnsetListener(OnsetListener listener) {
00077 listeners.remove(listener);
00078 }
00079 protected void notifyListeners(long frAddr, int zeroFrames) {
00080 for(int i=0; i<listeners.size(); i++)
00081 ((OnsetListener)listeners.get(i)).newOnset(frAddr, zeroFrames);
00082 }
00083
00084
00085
00086
00087 public void newFrame(STFT stft, long newestFrame) {
00088
00089 for(int i=0; i<histLen+1; i++) {
00090 history[i] = stft.getFrame(lastSeen+1-histLen+i);
00091 if(history[i] == null)
00092 history[i] = new double[stft.getRows()];
00093 }
00094
00095
00096 for(long fr = lastSeen+1; fr <= newestFrame; fr++) {
00097 double result;
00098 int curOns = (int)(fr % onsets.length);
00099 onsets[curOns] = 0;
00100
00101 for(int band=0; band<history[0].length; band++) {
00102 result = 0;
00103 for(int i=0; i<histLen; i++)
00104 result += Math.abs(history[i][band] - history[histLen][band]);
00105
00106
00107 if(result > bandThresh*state[band])
00108 ++onsets[curOns];
00109
00110
00111 state[band] = adaptation*result + (1-adaptation)*state[band];
00112 }
00113
00114
00115 for(int i=0; i<histLen; i++)
00116 history[i] = history[i+1];
00117 history[histLen] = stft.getFrame(fr);
00118 }
00119
00120 checkOnsets(lastSeen, newestFrame);
00121
00122
00123 lastSeen = newestFrame;
00124 }
00125
00126 public void checkOnsets(long lastSeen, long newestFrame) {
00127
00128
00129 for(long fr = lastSeen+1; fr <= newestFrame; fr++) {
00130 int curOns = (int)(fr % onsets.length);
00131
00132 if(onsets[curOns] > bandFrac*state.length) {
00133
00134
00135 notifyListeners(fr, 0);
00136 }
00137 }
00138 }
00139 }