yonge 3 년 전
부모
커밋
7d5c8f1c7c

+ 113 - 127
audio-analysis/src/main/java/com/yonge/netty/dto/UserChannelContext.java

@@ -7,6 +7,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
@@ -57,7 +58,7 @@ public class UserChannelContext {
 	
 	private List<SectionAnalysis> doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
 	
-	private List<ChunkAnalysis> chunkAnalysisList = new ArrayList<ChunkAnalysis>();
+	private List<ChunkAnalysis> totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 	
 	private byte[] channelBufferBytes = new byte[0];
 	
@@ -65,8 +66,6 @@ public class UserChannelContext {
 	
 	private double receivedTime;
 	
-	private List<ChunkAnalysis> lastChunkAnalysisList = new ArrayList<ChunkAnalysis>();
-	
 	private HardLevelEnum hardLevel = HardLevelEnum.ADVANCED;
 	
 	public void init(String platform, String heardLevel, int subjectId, int beatDuration) {
@@ -148,11 +147,10 @@ public class UserChannelContext {
 		channelBufferBytes = new byte[0];
 		doneNoteAnalysisList = new ArrayList<NoteAnalysis>();
 		doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
-		chunkAnalysisList = new ArrayList<ChunkAnalysis>();
+		totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 		recordId = null;
 		playTime = 0;
 		receivedTime = 0;
-		lastChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 	}
 	
 	public MusicXmlBasicInfo getMusicXmlBasicInfo(Integer songId){
@@ -301,69 +299,43 @@ public class UserChannelContext {
 		evaluatingSectionIndex.set(noteAnalysis.getSectionIndex());
 		
 		if (noteAnalysis.getMusicalNotesIndex() >= 0 && noteAnalysis.getMusicalNotesIndex() <= getTotalMusicNoteIndex(null)) {
-
-			if (playTime >= (musicXmlNote.getDuration() + musicXmlNote.getTimeStamp())) {
-
-				LOGGER.info("------ Frequency:{}  splDb:{}  Power:{}  amplitude:{} time:{}------", playFrequency, splDb, power, amplitude, playTime);
-				
-				ChunkAnalysis lastChunkAnalysis = new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude);
-				
-				if(Math.abs(chunkAnalysisList.get(chunkAnalysisList.size() - 1).getFrequency() - lastChunkAnalysis.getFrequency()) > hardLevel.getFrequencyThreshold()){
-					lastChunkAnalysis.setFrequency(-1);
-				}
-				if(chunkAnalysisList.get(chunkAnalysisList.size() - 1).getAmplitude() + 2 < lastChunkAnalysis.getAmplitude()){
-					lastChunkAnalysis.setPeak(true);
-				}
-				
-				//每个音符最后一个块
-				lastChunkAnalysisList.add(lastChunkAnalysis);
-				if(noteAnalysis.getMusicalNotesIndex() > 0){
-					lastChunkAnalysis = lastChunkAnalysisList.get(noteAnalysis.getMusicalNotesIndex() - 1);
-				}else{
-					lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
+			
+			LOGGER.info("Frequency:{}  splDb:{}  Power:{}  amplitude:{}  rms:{}  time:{}", playFrequency, splDb, power, amplitude, rms, playTime);
+			
+			ChunkAnalysis chunkAnalysis = new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude);
+			
+			if(totalChunkAnalysisList.size() > 0){
+				if(totalChunkAnalysisList.get(totalChunkAnalysisList.size() - 1).getAmplitude() + 2 < chunkAnalysis.getAmplitude()){
+					chunkAnalysis.setPeak(true);//只针对打击乐
 				}
+			}
+			totalChunkAnalysisList.add(chunkAnalysis);
+			
+			if (playTime >= (musicXmlNote.getDuration() + musicXmlNote.getTimeStamp())) {
 
 				if (musicXmlNote.getDontEvaluating()) {
 					noteAnalysis.setIgnore(true);
 				}
 				
-				if(chunkAnalysisList.size() == 0){// 延音线
-					
-				}
-				
-				noteAnalysis.setPlayFrequency(computeFrequency(chunkAnalysisList, lastChunkAnalysis, hardLevel.getFrequencyThreshold()));
+				noteAnalysis.setPlayFrequency(computeFrequency(musicXmlNote));
 				
 				//判断节奏(音符持续时间内有不间断的音高,就节奏正确)
 				boolean tempo = true;
 				if (subjectId == 23 || subjectId == 113) {
-					if (musicXmlNote.getFrequency() == -1) {// 休止符
-						tempo = chunkAnalysisList.stream().filter(t -> t.getAmplitude() > hardLevel.getAmplitudeThreshold()).count() <= 0;
-					}else{
-						tempo = computeTempoWithAmplitude2(musicXmlNote, chunkAnalysisList, lastChunkAnalysis);
-					}
+					tempo = computeTempoWithAmplitude2(musicXmlNote);
 				}else{
-					if (musicXmlNote.getFrequency() == -1) {// 休止符
-						tempo = chunkAnalysisList.stream().filter(t -> t.getFrequency() > 100).count() <= 1;
-					}else{
-						tempo = computeTempoWithFrequency(musicXmlNote, chunkAnalysisList, lastChunkAnalysis);
-					}
+					tempo = computeTempoWithFrequency(musicXmlNote);
 				}
 				
-				noteAnalysis.setDurationTime(chunkAnalysisList.stream().mapToDouble(t -> t.getDurationTime()).sum());
-				
 				noteAnalysis.setTempo(tempo);
 				
-				evaluateForNote(noteAnalysis);
+				evaluateForNote(musicXmlNote, noteAnalysis);
 
 				LOGGER.info("当前音符下标[{}] 预计频率:{} 实际频率:{} 节奏:{}", noteAnalysis.getMusicalNotesIndex(), musicXmlNote.getFrequency(), noteAnalysis.getPlayFrequency(),
 						noteAnalysis.isTempo());
 				
 				doneNoteAnalysisList.add(noteAnalysis);
 				
-				//lastChunkAnalysis = chunkAnalysisList.get(chunkAnalysisList.size() - 1);
-				
-				chunkAnalysisList.clear();
-
 				// 准备处理下一个音符
 				int nextNoteIndex = musicXmlNote.getMusicalNotesIndex() + 1;
 				float nextNoteFrequence = -1;
@@ -378,12 +350,6 @@ public class UserChannelContext {
 
 				noteAnalysis = nextNoteAnalysis;
 
-			} else {
-				
-				LOGGER.info("Frequency:{}  splDb:{}  Power:{}  amplitude:{}  rms:{}", playFrequency, splDb, power, amplitude, rms);
-				
-				chunkAnalysisList.add(new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude));
-				
 			}
 
 			setProcessingNote(noteAnalysis);
@@ -471,8 +437,14 @@ public class UserChannelContext {
 	}
 	
 
-	public void evaluateForNote(NoteAnalysis noteAnalysis) {
-
+	public void evaluateForNote(MusicXmlNote musicXmlNote, NoteAnalysis noteAnalysis) {
+		
+		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
+		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
+		double startTime = musicXmlNote.getTimeStamp() - floatingRange;
+		
+		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
+		
 		double playDurationTime = 0;
 		
 		if (subjectId == 23 || subjectId == 113) {
@@ -563,7 +535,32 @@ public class UserChannelContext {
 		}
 	}
 	
-	private int computeFrequency(List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis, int offsetRange) {
+	private int computeFrequency(MusicXmlNote musicXmlNote) {
+		
+		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
+		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
+		double startTime = musicXmlNote.getTimeStamp() - floatingRange;
+		
+		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
+		
+		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
+			return -1;
+		}
+		
+		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
+		
+		LOGGER.info("-------startTime:{}  endTime:{}------", firstChunkAnalysis.getStartTime(), chunkAnalysisList.get(chunkAnalysisList.size() - 1)
+				.getEndTime());
+		
+		Optional<ChunkAnalysis> chunkAnalysisOptional = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getEndTime()) == Double.doubleToLongBits(firstChunkAnalysis.getStartTime())).findFirst();
+
+		ChunkAnalysis lastChunkAnalysis = null;
+		if (chunkAnalysisOptional.isPresent()) {
+			lastChunkAnalysis = chunkAnalysisOptional.get();
+		}
+		if(lastChunkAnalysis == null){
+			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
+		}
 		
 		List<ChunkAnalysis> chunkList = new ArrayList<ChunkAnalysis>(chunkAnalysisList);
 		
@@ -573,7 +570,7 @@ public class UserChannelContext {
 			int lastFrequency = lastChunkAnalysis.getFrequency();
 			Iterator<ChunkAnalysis> iterable = chunkList.iterator();
 			while (iterable.hasNext()) {
-				if (Math.abs(lastFrequency - iterable.next().getFrequency()) > offsetRange) {
+				if (Math.abs(lastFrequency - iterable.next().getFrequency()) > hardLevel.getFrequencyThreshold()) {
 					break;
 				}
 				iterable.remove();
@@ -608,7 +605,7 @@ public class UserChannelContext {
 		for (int i = 1; i < chunkFrequencyList.size(); i++) {
 			tempFrequency = chunkFrequencyList.get(i);
 
-			if (Math.abs(avgFrequency - tempFrequency) > offsetRange) {
+			if (Math.abs(avgFrequency - tempFrequency) > hardLevel.getFrequencyThreshold()) {
 
 				avgFrequency = totalFrequency / chunkSize;
 
@@ -644,7 +641,34 @@ public class UserChannelContext {
 		return frequency;
 	}
 	
-	private boolean computeTempoWithFrequency(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis){
+	private boolean computeTempoWithFrequency(MusicXmlNote musicXmlNote){
+		
+		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
+		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
+		double startTime = musicXmlNote.getTimeStamp() - floatingRange;
+		
+		List<ChunkAnalysis>  chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
+		
+		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
+			return false;
+		}
+		
+		if (musicXmlNote.getFrequency() == -1) {// 休止符
+			return chunkAnalysisList.stream().filter(t -> t.getFrequency() > 100).count() <= 1;
+		}
+		
+		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
+		
+		Optional<ChunkAnalysis> chunkAnalysisOptional = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getEndTime()) == Double.doubleToLongBits(firstChunkAnalysis.getStartTime())).findFirst();
+
+		ChunkAnalysis lastChunkAnalysis = null;
+		if (chunkAnalysisOptional.isPresent()) {
+			lastChunkAnalysis = chunkAnalysisOptional.get();
+		}
+		
+		if(lastChunkAnalysis == null){
+			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
+		}
 		
 		List<ChunkAnalysis> chunkList = new ArrayList<ChunkAnalysis>(chunkAnalysisList);
 		
@@ -701,7 +725,7 @@ public class UserChannelContext {
 		
 		if (tempo) {
 			// 判断进入时间点
-			if((chunkAnalysisList.size() - chunkList.size() + firstPeakIndex) * 100 /chunkAnalysisList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())){
+			if((chunkAnalysisList.size() - chunkList.size() + firstPeakIndex) * 100 /chunkAnalysisList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) * 2){
 				tempo = false;
 			}
 		}
@@ -709,14 +733,36 @@ public class UserChannelContext {
 		return tempo;
 	}
 	
-	private boolean computeTempoWithAmplitude2(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis) {
+	private boolean computeTempoWithAmplitude2(MusicXmlNote musicXmlNote) {
 
-		List<Integer> chunkAmplitudeList = chunkAnalysisList.stream().map(ChunkAnalysis::getAmplitude).collect(Collectors.toList());
+		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
+		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
+		double startTime = musicXmlNote.getTimeStamp() - floatingRange;
+		
+		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
+		
+		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
+			return false;
+		}
 
-		/*if (chunkAmplitudeList.size() <= 3) {
-			return chunkAmplitudeList.stream().filter(t -> t.floatValue() > hardLevel.getAmplitudeThreshold()).count() > 0;
-		}*/
+		if (musicXmlNote.getFrequency() == -1) {// 休止符
+			return chunkAnalysisList.stream().filter(t -> t.getAmplitude() > hardLevel.getAmplitudeThreshold()).count() <= 0;
+		}
+		
+		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
 		
+		Optional<ChunkAnalysis> chunkAnalysisOptional = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getEndTime()) == Double.doubleToLongBits(firstChunkAnalysis.getStartTime())).findFirst();
+
+		ChunkAnalysis lastChunkAnalysis = null;
+		if (chunkAnalysisOptional.isPresent()) {
+			lastChunkAnalysis = chunkAnalysisOptional.get();
+		}
+		if(lastChunkAnalysis == null){
+			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
+		}
+		
+		List<Integer> chunkAmplitudeList = chunkAnalysisList.stream().map(ChunkAnalysis::getAmplitude).collect(Collectors.toList());
+
 		chunkAmplitudeList.add(0, lastChunkAnalysis.getAmplitude());
 		
 		// 检测是否有多个波峰
@@ -753,7 +799,7 @@ public class UserChannelContext {
 		
 		if (tempo) {
 			// 判断进入时间点
-			if((firstPeakIndex - 1) * 100 /chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())){
+			if((firstPeakIndex - 1) * 100 /chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) * 2){
 				tempo = false;
 			}
 		}
@@ -761,72 +807,12 @@ public class UserChannelContext {
 		return tempo;
 	}
 	
-	private boolean computeTempoWithAmplitude(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis) {
-
-		boolean tempo = false;
-
-		List<Integer> chunkAmplitudeList = chunkAnalysisList.stream().map(ChunkAnalysis::getAmplitude).collect(Collectors.toList());
-
-		if (chunkAmplitudeList.size() < 3) {
-			return chunkAmplitudeList.stream().filter(t -> t.floatValue() > hardLevel.getAmplitudeThreshold()).count() > 0;
-		}
-		
-		chunkAmplitudeList.add(0, lastChunkAnalysis.getAmplitude());
-
-		// 检测是否有多个波峰
-		int peakSize = 0;
-		int minPeakIndex = -1;
-		for (int i = 1; i < chunkAmplitudeList.size(); i++) {
-			if (chunkAmplitudeList.get(i) < hardLevel.getAmplitudeThreshold()) {
-				continue;
-			}
-			if (i == chunkAmplitudeList.size() - 1) {
-				if (chunkAmplitudeList.get(i) > chunkAmplitudeList.get(i - 1)) {
-					peakSize++;
-					if (minPeakIndex == -1 || minPeakIndex > i) {
-						minPeakIndex = i;
-					}
-				}
-			} else {
-				if (chunkAmplitudeList.get(i - 1) < chunkAmplitudeList.get(i) && chunkAmplitudeList.get(i) >= chunkAmplitudeList.get(i + 1)) {
-					//if(Math.abs(chunkAmplitudeList.get(i - 1) - chunkAmplitudeList.get(i)) > 2 || Math.abs(chunkAmplitudeList.get(i) - chunkAmplitudeList.get(i + 1)) > 2){
-						peakSize++;
-						if (minPeakIndex == -1 || minPeakIndex > i) {
-							minPeakIndex = i;
-						}
-					//}
-				}
-			}
-		}
-
-		if (peakSize == 1) {
-			if (lastChunkAnalysis.isPeak() == false) {
-				tempo = true;
-			}
-		} else if (peakSize == 0) {
-			if (lastChunkAnalysis.isPeak()) {
-				tempo = true;
-			}
-		}
-
-		// 检测是否延迟进入
-		if (tempo == true) {
-			if (minPeakIndex * 100 / chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) && chunkAmplitudeList.size() > 3) {
-				tempo = false;
-			}
-		}
-
-		return tempo;
-	}
-	
 	public static void main(String[] args) {
 		UserChannelContext context = new UserChannelContext();
 		
 		//int[] frequencys = {286,291,291,291,291,291,291};
 		int[] frequencys = {312,43,295,294,294,295};
 		
-		ChunkAnalysis lastChunkAnalysis = new ChunkAnalysis(624, 0, 0);
-		
 		List<ChunkAnalysis> chunkAnalysisList = new ArrayList<ChunkAnalysis>();
 		for(int f : frequencys) {
 			chunkAnalysisList.add(new ChunkAnalysis(f, 0, 0));
@@ -836,7 +822,7 @@ public class UserChannelContext {
 		musicXmlNote.setDenominator(1);
 		
 		//System.out.println(context.computeFrequency(chunkAnalysisList, lastChunkAnalysis, 5));
-		System.out.println(context.computeTempoWithFrequency(musicXmlNote, chunkAnalysisList, lastChunkAnalysis));
+		System.out.println(context.computeTempoWithFrequency(musicXmlNote));
 	}
 	
 }

+ 128 - 94
audio-analysis/src/main/java/com/yonge/netty/dto/UserChannelContext2.java

@@ -30,7 +30,7 @@ import com.yonge.netty.server.processor.WaveformWriter;
  */
 public class UserChannelContext2 {
 	
-	private final static Logger LOGGER = LoggerFactory.getLogger(UserChannelContext2.class);
+	private final static Logger LOGGER = LoggerFactory.getLogger(UserChannelContext.class);
 	
 	private int offsetMS = 350;
 	
@@ -57,7 +57,7 @@ public class UserChannelContext2 {
 	
 	private List<SectionAnalysis> doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
 	
-	private List<ChunkAnalysis> totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
+	private List<ChunkAnalysis> chunkAnalysisList = new ArrayList<ChunkAnalysis>();
 	
 	private byte[] channelBufferBytes = new byte[0];
 	
@@ -65,6 +65,8 @@ public class UserChannelContext2 {
 	
 	private double receivedTime;
 	
+	private List<ChunkAnalysis> lastChunkAnalysisList = new ArrayList<ChunkAnalysis>();
+	
 	private HardLevelEnum hardLevel = HardLevelEnum.ADVANCED;
 	
 	public void init(String platform, String heardLevel, int subjectId, int beatDuration) {
@@ -146,10 +148,11 @@ public class UserChannelContext2 {
 		channelBufferBytes = new byte[0];
 		doneNoteAnalysisList = new ArrayList<NoteAnalysis>();
 		doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
-		totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
+		chunkAnalysisList = new ArrayList<ChunkAnalysis>();
 		recordId = null;
 		playTime = 0;
 		receivedTime = 0;
+		lastChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 	}
 	
 	public MusicXmlBasicInfo getMusicXmlBasicInfo(Integer songId){
@@ -298,43 +301,69 @@ public class UserChannelContext2 {
 		evaluatingSectionIndex.set(noteAnalysis.getSectionIndex());
 		
 		if (noteAnalysis.getMusicalNotesIndex() >= 0 && noteAnalysis.getMusicalNotesIndex() <= getTotalMusicNoteIndex(null)) {
-			
-			LOGGER.info("Frequency:{}  splDb:{}  Power:{}  amplitude:{}  rms:{}  time:{}", playFrequency, splDb, power, amplitude, rms, playTime);
-			
-			ChunkAnalysis chunkAnalysis = new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude);
-			
-			if(totalChunkAnalysisList.size() > 0){
-				if(totalChunkAnalysisList.get(totalChunkAnalysisList.size() - 1).getAmplitude() + 2 < chunkAnalysis.getAmplitude()){
-					chunkAnalysis.setPeak(true);//只针对打击乐
-				}
-			}
-			totalChunkAnalysisList.add(chunkAnalysis);
-			
+
 			if (playTime >= (musicXmlNote.getDuration() + musicXmlNote.getTimeStamp())) {
 
+				LOGGER.info("------ Frequency:{}  splDb:{}  Power:{}  amplitude:{} time:{}------", playFrequency, splDb, power, amplitude, playTime);
+				
+				ChunkAnalysis lastChunkAnalysis = new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude);
+				
+				if(Math.abs(chunkAnalysisList.get(chunkAnalysisList.size() - 1).getFrequency() - lastChunkAnalysis.getFrequency()) > hardLevel.getFrequencyThreshold()){
+					lastChunkAnalysis.setFrequency(-1);
+				}
+				if(chunkAnalysisList.get(chunkAnalysisList.size() - 1).getAmplitude() + 2 < lastChunkAnalysis.getAmplitude()){
+					lastChunkAnalysis.setPeak(true);
+				}
+				
+				//每个音符最后一个块
+				lastChunkAnalysisList.add(lastChunkAnalysis);
+				if(noteAnalysis.getMusicalNotesIndex() > 0){
+					lastChunkAnalysis = lastChunkAnalysisList.get(noteAnalysis.getMusicalNotesIndex() - 1);
+				}else{
+					lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
+				}
+
 				if (musicXmlNote.getDontEvaluating()) {
 					noteAnalysis.setIgnore(true);
 				}
 				
-				noteAnalysis.setPlayFrequency(computeFrequency(musicXmlNote));
+				if(chunkAnalysisList.size() == 0){// 延音线
+					
+				}
+				
+				noteAnalysis.setPlayFrequency(computeFrequency(chunkAnalysisList, lastChunkAnalysis, hardLevel.getFrequencyThreshold()));
 				
 				//判断节奏(音符持续时间内有不间断的音高,就节奏正确)
 				boolean tempo = true;
 				if (subjectId == 23 || subjectId == 113) {
-					tempo = computeTempoWithAmplitude2(musicXmlNote);
+					if (musicXmlNote.getFrequency() == -1) {// 休止符
+						tempo = chunkAnalysisList.stream().filter(t -> t.getAmplitude() > hardLevel.getAmplitudeThreshold()).count() <= 0;
+					}else{
+						tempo = computeTempoWithAmplitude2(musicXmlNote, chunkAnalysisList, lastChunkAnalysis);
+					}
 				}else{
-					tempo = computeTempoWithFrequency(musicXmlNote);
+					if (musicXmlNote.getFrequency() == -1) {// 休止符
+						tempo = chunkAnalysisList.stream().filter(t -> t.getFrequency() > 100).count() <= 1;
+					}else{
+						tempo = computeTempoWithFrequency(musicXmlNote, chunkAnalysisList, lastChunkAnalysis);
+					}
 				}
 				
+				noteAnalysis.setDurationTime(chunkAnalysisList.stream().mapToDouble(t -> t.getDurationTime()).sum());
+				
 				noteAnalysis.setTempo(tempo);
 				
-				evaluateForNote(musicXmlNote, noteAnalysis);
+				evaluateForNote(noteAnalysis);
 
 				LOGGER.info("当前音符下标[{}] 预计频率:{} 实际频率:{} 节奏:{}", noteAnalysis.getMusicalNotesIndex(), musicXmlNote.getFrequency(), noteAnalysis.getPlayFrequency(),
 						noteAnalysis.isTempo());
 				
 				doneNoteAnalysisList.add(noteAnalysis);
 				
+				//lastChunkAnalysis = chunkAnalysisList.get(chunkAnalysisList.size() - 1);
+				
+				chunkAnalysisList.clear();
+
 				// 准备处理下一个音符
 				int nextNoteIndex = musicXmlNote.getMusicalNotesIndex() + 1;
 				float nextNoteFrequence = -1;
@@ -349,6 +378,12 @@ public class UserChannelContext2 {
 
 				noteAnalysis = nextNoteAnalysis;
 
+			} else {
+				
+				LOGGER.info("Frequency:{}  splDb:{}  Power:{}  amplitude:{}  rms:{}", playFrequency, splDb, power, amplitude, rms);
+				
+				chunkAnalysisList.add(new ChunkAnalysis(playTime - durationTime, playTime, playFrequency, splDb, power, amplitude));
+				
 			}
 
 			setProcessingNote(noteAnalysis);
@@ -436,14 +471,8 @@ public class UserChannelContext2 {
 	}
 	
 
-	public void evaluateForNote(MusicXmlNote musicXmlNote, NoteAnalysis noteAnalysis) {
-		
-		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
-		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
-		double startTime = musicXmlNote.getTimeStamp() + floatingRange;
-		
-		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> t.getStartTime() >= startTime && t.getEndTime() <= endTime).collect(Collectors.toList());
-		
+	public void evaluateForNote(NoteAnalysis noteAnalysis) {
+
 		double playDurationTime = 0;
 		
 		if (subjectId == 23 || subjectId == 113) {
@@ -534,24 +563,7 @@ public class UserChannelContext2 {
 		}
 	}
 	
-	private int computeFrequency(MusicXmlNote musicXmlNote) {
-		
-		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
-		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
-		double startTime = musicXmlNote.getTimeStamp() + floatingRange;
-		
-		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> t.getStartTime() >= startTime && t.getEndTime() <= endTime).collect(Collectors.toList());
-		
-		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
-			return -1;
-		}
-		
-		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
-		
-		ChunkAnalysis lastChunkAnalysis = totalChunkAnalysisList.stream().filter(t -> t.getEndTime() == firstChunkAnalysis.getStartTime()).findFirst().get();
-		if(lastChunkAnalysis == null){
-			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
-		}
+	private int computeFrequency(List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis, int offsetRange) {
 		
 		List<ChunkAnalysis> chunkList = new ArrayList<ChunkAnalysis>(chunkAnalysisList);
 		
@@ -561,7 +573,7 @@ public class UserChannelContext2 {
 			int lastFrequency = lastChunkAnalysis.getFrequency();
 			Iterator<ChunkAnalysis> iterable = chunkList.iterator();
 			while (iterable.hasNext()) {
-				if (Math.abs(lastFrequency - iterable.next().getFrequency()) > hardLevel.getFrequencyThreshold()) {
+				if (Math.abs(lastFrequency - iterable.next().getFrequency()) > offsetRange) {
 					break;
 				}
 				iterable.remove();
@@ -596,7 +608,7 @@ public class UserChannelContext2 {
 		for (int i = 1; i < chunkFrequencyList.size(); i++) {
 			tempFrequency = chunkFrequencyList.get(i);
 
-			if (Math.abs(avgFrequency - tempFrequency) > hardLevel.getFrequencyThreshold()) {
+			if (Math.abs(avgFrequency - tempFrequency) > offsetRange) {
 
 				avgFrequency = totalFrequency / chunkSize;
 
@@ -632,28 +644,7 @@ public class UserChannelContext2 {
 		return frequency;
 	}
 	
-	private boolean computeTempoWithFrequency(MusicXmlNote musicXmlNote){
-		
-		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
-		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
-		double startTime = musicXmlNote.getTimeStamp() + floatingRange;
-		
-		List<ChunkAnalysis>  chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> t.getStartTime() >= startTime && t.getEndTime() <= endTime).collect(Collectors.toList());
-		
-		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
-			return false;
-		}
-		
-		if (musicXmlNote.getFrequency() == -1) {// 休止符
-			return chunkAnalysisList.stream().filter(t -> t.getFrequency() > 100).count() <= 1;
-		}
-		
-		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
-		
-		ChunkAnalysis lastChunkAnalysis = totalChunkAnalysisList.stream().filter(t -> t.getEndTime() == firstChunkAnalysis.getStartTime()).findFirst().get();
-		if(lastChunkAnalysis == null){
-			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
-		}
+	private boolean computeTempoWithFrequency(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis){
 		
 		List<ChunkAnalysis> chunkList = new ArrayList<ChunkAnalysis>(chunkAnalysisList);
 		
@@ -710,7 +701,7 @@ public class UserChannelContext2 {
 		
 		if (tempo) {
 			// 判断进入时间点
-			if((chunkAnalysisList.size() - chunkList.size() + firstPeakIndex) * 100 /chunkAnalysisList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) * 2){
+			if((chunkAnalysisList.size() - chunkList.size() + firstPeakIndex) * 100 /chunkAnalysisList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())){
 				tempo = false;
 			}
 		}
@@ -718,31 +709,14 @@ public class UserChannelContext2 {
 		return tempo;
 	}
 	
-	private boolean computeTempoWithAmplitude2(MusicXmlNote musicXmlNote) {
+	private boolean computeTempoWithAmplitude2(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis) {
 
-		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
-		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() - floatingRange;
-		double startTime = musicXmlNote.getTimeStamp() + floatingRange;
-		
-		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> t.getStartTime() >= startTime && t.getEndTime() <= endTime).collect(Collectors.toList());
-		
-		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
-			return false;
-		}
-
-		if (musicXmlNote.getFrequency() == -1) {// 休止符
-			return chunkAnalysisList.stream().filter(t -> t.getAmplitude() > hardLevel.getAmplitudeThreshold()).count() <= 0;
-		}
-		
-		ChunkAnalysis firstChunkAnalysis = chunkAnalysisList.get(0);
-		
-		ChunkAnalysis lastChunkAnalysis = totalChunkAnalysisList.stream().filter(t -> t.getEndTime() == firstChunkAnalysis.getStartTime()).findFirst().get();
-		if(lastChunkAnalysis == null){
-			lastChunkAnalysis = new ChunkAnalysis(0, 0, -1, 0, 0, 0);
-		}
-		
 		List<Integer> chunkAmplitudeList = chunkAnalysisList.stream().map(ChunkAnalysis::getAmplitude).collect(Collectors.toList());
 
+		/*if (chunkAmplitudeList.size() <= 3) {
+			return chunkAmplitudeList.stream().filter(t -> t.floatValue() > hardLevel.getAmplitudeThreshold()).count() > 0;
+		}*/
+		
 		chunkAmplitudeList.add(0, lastChunkAnalysis.getAmplitude());
 		
 		// 检测是否有多个波峰
@@ -779,7 +753,7 @@ public class UserChannelContext2 {
 		
 		if (tempo) {
 			// 判断进入时间点
-			if((firstPeakIndex - 1) * 100 /chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) * 2){
+			if((firstPeakIndex - 1) * 100 /chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())){
 				tempo = false;
 			}
 		}
@@ -787,12 +761,72 @@ public class UserChannelContext2 {
 		return tempo;
 	}
 	
+	private boolean computeTempoWithAmplitude(MusicXmlNote musicXmlNote, List<ChunkAnalysis> chunkAnalysisList, ChunkAnalysis lastChunkAnalysis) {
+
+		boolean tempo = false;
+
+		List<Integer> chunkAmplitudeList = chunkAnalysisList.stream().map(ChunkAnalysis::getAmplitude).collect(Collectors.toList());
+
+		if (chunkAmplitudeList.size() < 3) {
+			return chunkAmplitudeList.stream().filter(t -> t.floatValue() > hardLevel.getAmplitudeThreshold()).count() > 0;
+		}
+		
+		chunkAmplitudeList.add(0, lastChunkAnalysis.getAmplitude());
+
+		// 检测是否有多个波峰
+		int peakSize = 0;
+		int minPeakIndex = -1;
+		for (int i = 1; i < chunkAmplitudeList.size(); i++) {
+			if (chunkAmplitudeList.get(i) < hardLevel.getAmplitudeThreshold()) {
+				continue;
+			}
+			if (i == chunkAmplitudeList.size() - 1) {
+				if (chunkAmplitudeList.get(i) > chunkAmplitudeList.get(i - 1)) {
+					peakSize++;
+					if (minPeakIndex == -1 || minPeakIndex > i) {
+						minPeakIndex = i;
+					}
+				}
+			} else {
+				if (chunkAmplitudeList.get(i - 1) < chunkAmplitudeList.get(i) && chunkAmplitudeList.get(i) >= chunkAmplitudeList.get(i + 1)) {
+					//if(Math.abs(chunkAmplitudeList.get(i - 1) - chunkAmplitudeList.get(i)) > 2 || Math.abs(chunkAmplitudeList.get(i) - chunkAmplitudeList.get(i + 1)) > 2){
+						peakSize++;
+						if (minPeakIndex == -1 || minPeakIndex > i) {
+							minPeakIndex = i;
+						}
+					//}
+				}
+			}
+		}
+
+		if (peakSize == 1) {
+			if (lastChunkAnalysis.isPeak() == false) {
+				tempo = true;
+			}
+		} else if (peakSize == 0) {
+			if (lastChunkAnalysis.isPeak()) {
+				tempo = true;
+			}
+		}
+
+		// 检测是否延迟进入
+		if (tempo == true) {
+			if (minPeakIndex * 100 / chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) && chunkAmplitudeList.size() > 3) {
+				tempo = false;
+			}
+		}
+
+		return tempo;
+	}
+	
 	public static void main(String[] args) {
 		UserChannelContext2 context = new UserChannelContext2();
 		
 		//int[] frequencys = {286,291,291,291,291,291,291};
 		int[] frequencys = {312,43,295,294,294,295};
 		
+		ChunkAnalysis lastChunkAnalysis = new ChunkAnalysis(624, 0, 0);
+		
 		List<ChunkAnalysis> chunkAnalysisList = new ArrayList<ChunkAnalysis>();
 		for(int f : frequencys) {
 			chunkAnalysisList.add(new ChunkAnalysis(f, 0, 0));
@@ -802,7 +836,7 @@ public class UserChannelContext2 {
 		musicXmlNote.setDenominator(1);
 		
 		//System.out.println(context.computeFrequency(chunkAnalysisList, lastChunkAnalysis, 5));
-		System.out.println(context.computeTempoWithFrequency(musicXmlNote));
+		System.out.println(context.computeTempoWithFrequency(musicXmlNote, chunkAnalysisList, lastChunkAnalysis));
 	}
 	
 }