|  | @@ -1,841 +0,0 @@
 | 
	
		
			
				|  |  | -package com.yonge.netty.dto;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import java.math.BigDecimal;
 | 
	
		
			
				|  |  | -import java.util.ArrayList;
 | 
	
		
			
				|  |  | -import java.util.Comparator;
 | 
	
		
			
				|  |  | -import java.util.HashMap;
 | 
	
		
			
				|  |  | -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;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import javax.sound.sampled.AudioFormat;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import org.slf4j.Logger;
 | 
	
		
			
				|  |  | -import org.slf4j.LoggerFactory;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import com.yonge.audio.analysis.Signals;
 | 
	
		
			
				|  |  | -import com.yonge.audio.analysis.detector.YINPitchDetector;
 | 
	
		
			
				|  |  | -import com.yonge.audio.utils.ArrayUtil;
 | 
	
		
			
				|  |  | -import com.yonge.netty.dto.NoteAnalysis.NoteErrorType;
 | 
	
		
			
				|  |  | -import com.yonge.netty.entity.MusicXmlBasicInfo;
 | 
	
		
			
				|  |  | -import com.yonge.netty.entity.MusicXmlNote;
 | 
	
		
			
				|  |  | -import com.yonge.netty.entity.MusicXmlSection;
 | 
	
		
			
				|  |  | -import com.yonge.netty.server.processor.WaveformWriter;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * 用户通道上下文
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -public class UserChannelContext3 {
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private final static Logger LOGGER = LoggerFactory.getLogger(UserChannelContext.class);
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private double standardFrequecy = 442;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private int offsetMS;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private double dynamicOffset;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private String platform;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private Long recordId;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private Integer subjectId;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private int beatDuration;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private int beatByteLength;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private boolean delayProcessed;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	// 曲目与musicxml对应关系
 | 
	
		
			
				|  |  | -	private ConcurrentHashMap<Integer, MusicXmlBasicInfo> songMusicXmlMap = new ConcurrentHashMap<Integer, MusicXmlBasicInfo>();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private WaveformWriter waveFileProcessor;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private NoteAnalysis processingNote = new NoteAnalysis(0, 0, -1);
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private AtomicInteger evaluatingSectionIndex = new AtomicInteger(0);
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private List<NoteAnalysis> doneNoteAnalysisList = new ArrayList<NoteAnalysis>();
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private List<SectionAnalysis> doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private List<ChunkAnalysis> totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private byte[] channelBufferBytes = new byte[0];
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private double playTime;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private double receivedTime;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private HardLevelEnum hardLevel = HardLevelEnum.ADVANCED;
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private NotePlayResult queryNoteFrequency(MusicXmlNote xmlNote, double playFrequency) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		NotePlayResult result = new NotePlayResult();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		boolean status = false;
 | 
	
		
			
				|  |  | -		double migrationRate = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (Math.round(xmlNote.getFrequency()) == Math.round(playFrequency)) {
 | 
	
		
			
				|  |  | -			status = true;
 | 
	
		
			
				|  |  | -			migrationRate = 0;
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			NoteFrequencyRange noteFrequencyRange = new NoteFrequencyRange(standardFrequecy, xmlNote.getFrequency());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if (noteFrequencyRange.getMinFrequency() > playFrequency || playFrequency > noteFrequencyRange.getMaxFrequency()) {
 | 
	
		
			
				|  |  | -				status = false;
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				status = true;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				if (Math.round(playFrequency) < Math.round(xmlNote.getFrequency())) {
 | 
	
		
			
				|  |  | -					double min = Math.abs(xmlNote.getFrequency() - noteFrequencyRange.getMinFrequency()) / 2;
 | 
	
		
			
				|  |  | -					migrationRate = Math.abs(playFrequency - xmlNote.getFrequency()) / min;
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					double max = Math.abs(xmlNote.getFrequency() - noteFrequencyRange.getMaxFrequency()) / 2;
 | 
	
		
			
				|  |  | -					migrationRate = Math.abs(playFrequency - xmlNote.getFrequency()) / max;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		result.setStatus(status);
 | 
	
		
			
				|  |  | -		result.setMigrationRate(migrationRate);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return result;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public void init(String platform, String heardLevel, int subjectId, int beatDuration) {
 | 
	
		
			
				|  |  | -		this.platform = platform;
 | 
	
		
			
				|  |  | -		this.subjectId = subjectId;
 | 
	
		
			
				|  |  | -		this.beatDuration = beatDuration;
 | 
	
		
			
				|  |  | -		this.beatByteLength = WaveformWriter.SAMPLE_RATE * WaveformWriter.BITS_PER_SAMPLE / 8 * beatDuration / 1000;
 | 
	
		
			
				|  |  | -		hardLevel = HardLevelEnum.valueOf(heardLevel);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public byte[] skipMetronome(byte[] datas) {
 | 
	
		
			
				|  |  | -		if (beatByteLength > 0) {
 | 
	
		
			
				|  |  | -			if (datas.length <= beatByteLength) {
 | 
	
		
			
				|  |  | -				beatByteLength -= datas.length;
 | 
	
		
			
				|  |  | -				return new byte[0];
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			if(beatByteLength % 2 != 0){
 | 
	
		
			
				|  |  | -				beatByteLength++;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			datas = ArrayUtil.extractByte(datas, beatByteLength, datas.length - 1);
 | 
	
		
			
				|  |  | -			beatByteLength = 0;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		return datas;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public Long getRecordId() {
 | 
	
		
			
				|  |  | -		return recordId;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void setRecordId(Long recordId) {
 | 
	
		
			
				|  |  | -		this.recordId = recordId;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public int getOffsetMS() {
 | 
	
		
			
				|  |  | -		return offsetMS;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void setOffsetMS(int offsetMS) {
 | 
	
		
			
				|  |  | -		this.offsetMS = offsetMS;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public HardLevelEnum getHardLevel() {
 | 
	
		
			
				|  |  | -		return hardLevel;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public ConcurrentHashMap<Integer, MusicXmlBasicInfo> getSongMusicXmlMap() {
 | 
	
		
			
				|  |  | -		return songMusicXmlMap;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public WaveformWriter getWaveFileProcessor() {
 | 
	
		
			
				|  |  | -		return waveFileProcessor;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void setWaveFileProcessor(WaveformWriter waveFileProcessor) {
 | 
	
		
			
				|  |  | -		this.waveFileProcessor = waveFileProcessor;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public NoteAnalysis getProcessingNote() {
 | 
	
		
			
				|  |  | -		return processingNote;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void setProcessingNote(NoteAnalysis processingNote) {
 | 
	
		
			
				|  |  | -		this.processingNote = processingNote;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public List<SectionAnalysis> getDoneSectionAnalysisList() {
 | 
	
		
			
				|  |  | -		return doneSectionAnalysisList;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public List<NoteAnalysis> getDoneNoteAnalysisList() {
 | 
	
		
			
				|  |  | -		return doneNoteAnalysisList;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void resetUserInfo() {
 | 
	
		
			
				|  |  | -		beatByteLength = WaveformWriter.SAMPLE_RATE * WaveformWriter.BITS_PER_SAMPLE / 8 * beatDuration / 1000;
 | 
	
		
			
				|  |  | -		waveFileProcessor = null;
 | 
	
		
			
				|  |  | -		processingNote = new NoteAnalysis(0,0,-1);
 | 
	
		
			
				|  |  | -		evaluatingSectionIndex = new AtomicInteger(0);
 | 
	
		
			
				|  |  | -		channelBufferBytes = new byte[0];
 | 
	
		
			
				|  |  | -		doneNoteAnalysisList = new ArrayList<NoteAnalysis>();
 | 
	
		
			
				|  |  | -		doneSectionAnalysisList = new ArrayList<SectionAnalysis>();
 | 
	
		
			
				|  |  | -		totalChunkAnalysisList = new ArrayList<ChunkAnalysis>();
 | 
	
		
			
				|  |  | -		recordId = null;
 | 
	
		
			
				|  |  | -		playTime = 0;
 | 
	
		
			
				|  |  | -		receivedTime = 0;
 | 
	
		
			
				|  |  | -		delayProcessed = false;
 | 
	
		
			
				|  |  | -		dynamicOffset = 0;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public MusicXmlBasicInfo getMusicXmlBasicInfo(Integer songId){
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = null;
 | 
	
		
			
				|  |  | -		if (songId == null) {
 | 
	
		
			
				|  |  | -			musicXmlBasicInfo = songMusicXmlMap.values().stream().findFirst().get();
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			musicXmlBasicInfo = songMusicXmlMap.get(songId);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		return musicXmlBasicInfo;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public MusicXmlSection getCurrentMusicSection(Integer songId, int sectionIndex){
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -		return musicXmlBasicInfo.getMusicXmlSectionMap().get(sectionIndex);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public MusicXmlNote getCurrentMusicNote(Integer songId, Integer noteIndex) {
 | 
	
		
			
				|  |  | -		if (songMusicXmlMap.size() == 0) {
 | 
	
		
			
				|  |  | -			return null;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		if(noteIndex == null){
 | 
	
		
			
				|  |  | -			noteIndex = processingNote.getMusicalNotesIndex();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		final int index = noteIndex;
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlBasicInfo != null && index <= getTotalMusicNoteIndex(null)) {
 | 
	
		
			
				|  |  | -			return musicXmlBasicInfo.getMusicXmlInfos().stream().filter(t -> t.getMusicalNotesIndex() == index).findFirst().get();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return null;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public int getTotalMusicNoteIndex(Integer songId) {
 | 
	
		
			
				|  |  | -		if (songMusicXmlMap.size() == 0) {
 | 
	
		
			
				|  |  | -			return -1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlBasicInfo != null) {
 | 
	
		
			
				|  |  | -			return musicXmlBasicInfo.getMusicXmlInfos().stream().map(t -> t.getMusicalNotesIndex()).distinct().max(Integer::compareTo).get();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return -1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public List<MusicXmlNote> getCurrentMusicSection(Integer songId, Integer sectionIndex) {
 | 
	
		
			
				|  |  | -		if (songMusicXmlMap.size() == 0) {
 | 
	
		
			
				|  |  | -			return null;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		if(sectionIndex == null){
 | 
	
		
			
				|  |  | -			sectionIndex = processingNote.getSectionIndex();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		final int index = sectionIndex;
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlBasicInfo != null) {
 | 
	
		
			
				|  |  | -			return musicXmlBasicInfo.getMusicXmlInfos().stream().filter(t -> t.getMusicalNotesIndex() == index)
 | 
	
		
			
				|  |  | -					.sorted(Comparator.comparing(MusicXmlNote::getMusicalNotesIndex)).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return null;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public int getTotalMusicSectionSize(Integer songId) {
 | 
	
		
			
				|  |  | -		if (songMusicXmlMap.size() == 0) {
 | 
	
		
			
				|  |  | -			return -1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlBasicInfo != null) {
 | 
	
		
			
				|  |  | -			return (int) musicXmlBasicInfo.getMusicXmlInfos().stream().map(t -> t.getMeasureIndex()).distinct().count();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return -1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public int getMusicSectionIndex(Integer songId, int musicXmlNoteIndex) {
 | 
	
		
			
				|  |  | -		if (songMusicXmlMap.size() == 0) {
 | 
	
		
			
				|  |  | -			return -1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if(getTotalMusicNoteIndex(null) < musicXmlNoteIndex){
 | 
	
		
			
				|  |  | -			return -1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		MusicXmlBasicInfo musicXmlBasicInfo = getMusicXmlBasicInfo(songId);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlBasicInfo != null) {
 | 
	
		
			
				|  |  | -			return musicXmlBasicInfo.getMusicXmlInfos().stream().filter(t -> t.getMusicalNotesIndex() == musicXmlNoteIndex).findFirst().get().getMeasureIndex();
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return -1;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public byte[] getChannelBufferBytes() {
 | 
	
		
			
				|  |  | -		return channelBufferBytes;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void setChannelBufferBytes(byte[] channelBufferBytes) {
 | 
	
		
			
				|  |  | -		this.channelBufferBytes = channelBufferBytes;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public AtomicInteger getEvaluatingSectionIndex() {
 | 
	
		
			
				|  |  | -		return evaluatingSectionIndex;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void handle(float[] samples, AudioFormat audioFormat){
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		YINPitchDetector frequencyDetector = new YINPitchDetector(samples.length , audioFormat.getSampleRate());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		int playFrequency = (int) frequencyDetector.getFrequency(samples);
 | 
	
		
			
				|  |  | -		int splDb = (int) Signals.soundPressureLevel(samples);
 | 
	
		
			
				|  |  | -		int power = (int) Signals.power(samples);
 | 
	
		
			
				|  |  | -		int amplitude = (int) Signals.norm(samples);
 | 
	
		
			
				|  |  | -		float rms = Signals.rms(samples);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double durationTime = 1000 * (samples.length * 2) / audioFormat.getSampleRate() / (audioFormat.getSampleSizeInBits() / 8);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		receivedTime += durationTime;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if(receivedTime < offsetMS){
 | 
	
		
			
				|  |  | -			return;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		playTime += durationTime;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		// 获取当前音符信息
 | 
	
		
			
				|  |  | -		MusicXmlNote musicXmlNote = getCurrentMusicNote(null,null);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (musicXmlNote == null) {
 | 
	
		
			
				|  |  | -			return;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		//取出当前处理中的音符信息
 | 
	
		
			
				|  |  | -		NoteAnalysis noteAnalysis = getProcessingNote();
 | 
	
		
			
				|  |  | -		if(noteAnalysis == null || noteAnalysis.getDurationTime() == 0) {
 | 
	
		
			
				|  |  | -			noteAnalysis = new NoteAnalysis(musicXmlNote.getMusicalNotesIndex(), musicXmlNote.getMeasureIndex(), (int)musicXmlNote.getFrequency(), musicXmlNote.getDuration());
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		evaluatingSectionIndex.set(noteAnalysis.getSectionIndex());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if (noteAnalysis.getMusicalNotesIndex() >= 0 && noteAnalysis.getMusicalNotesIndex() <= getTotalMusicNoteIndex(null)) {
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | -			LOGGER.info("delayPrcessed:{} dynamicOffset:{}  Frequency:{}  splDb:{}  Power:{}  amplitude:{}  rms:{}  time:{}", delayProcessed, dynamicOffset, 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(delayProcessed == false && chunkAnalysis.getFrequency() > 100){
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				delayProcessed = true;
 | 
	
		
			
				|  |  | -				//计算延迟偏移值
 | 
	
		
			
				|  |  | -				//playTime = musicXmlNote.getTimeStamp() + durationTime;
 | 
	
		
			
				|  |  | -				dynamicOffset = chunkAnalysis.getStartTime() - musicXmlNote.getTimeStamp();
 | 
	
		
			
				|  |  | -				/*if(100 * dynamicOffset / musicXmlNote.getDuration() > (100 - hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()))){
 | 
	
		
			
				|  |  | -					dynamicOffset = 0;
 | 
	
		
			
				|  |  | -				}*/
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | -			if (playTime >= (musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() + dynamicOffset)) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				if (musicXmlNote.getDontEvaluating()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setIgnore(true);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				noteAnalysis.setPlayFrequency(computeFrequency(musicXmlNote));
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				//判断节奏(音符持续时间内有不间断的音高,就节奏正确)
 | 
	
		
			
				|  |  | -				boolean tempo = true;
 | 
	
		
			
				|  |  | -				if (subjectId == 23 || subjectId == 113) {
 | 
	
		
			
				|  |  | -					tempo = computeTempoWithAmplitude2(musicXmlNote);
 | 
	
		
			
				|  |  | -				}else{
 | 
	
		
			
				|  |  | -					tempo = computeTempoWithFrequency(musicXmlNote);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				noteAnalysis.setTempo(tempo);
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				evaluateForNote(musicXmlNote, noteAnalysis);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				LOGGER.info("当前音符下标[{}] 预计频率:{} 实际频率:{} 节奏:{}", noteAnalysis.getMusicalNotesIndex(), musicXmlNote.getFrequency(), noteAnalysis.getPlayFrequency(),
 | 
	
		
			
				|  |  | -						noteAnalysis.isTempo());
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				doneNoteAnalysisList.add(noteAnalysis);
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				// 准备处理下一个音符
 | 
	
		
			
				|  |  | -				int nextNoteIndex = musicXmlNote.getMusicalNotesIndex() + 1;
 | 
	
		
			
				|  |  | -				float nextNoteFrequence = -1;
 | 
	
		
			
				|  |  | -				double standDuration = 0;
 | 
	
		
			
				|  |  | -				MusicXmlNote nextMusicXmlNote = getCurrentMusicNote(null, nextNoteIndex);
 | 
	
		
			
				|  |  | -				if(nextMusicXmlNote != null){
 | 
	
		
			
				|  |  | -					nextNoteFrequence = nextMusicXmlNote.getFrequency();
 | 
	
		
			
				|  |  | -					standDuration = nextMusicXmlNote.getDuration();
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				
 | 
	
		
			
				|  |  | -				NoteAnalysis nextNoteAnalysis = new NoteAnalysis(nextNoteIndex, getMusicSectionIndex(null, nextNoteIndex), (int)nextNoteFrequence, standDuration);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				noteAnalysis = nextNoteAnalysis;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			setProcessingNote(noteAnalysis);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public int evaluateForSection(int sectionIndex, int subjectId){
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		int score = -1;
 | 
	
		
			
				|  |  | -		if(doneSectionAnalysisList.size() >= getTotalMusicSectionSize(null)){
 | 
	
		
			
				|  |  | -			return score;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		//取出当前小节的所有音符
 | 
	
		
			
				|  |  | -		List<NoteAnalysis> noteAnalysisList = doneNoteAnalysisList.stream().filter(t -> t.getSectionIndex() == sectionIndex).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		long ignoreSize = noteAnalysisList.stream().filter(t -> t.isIgnore()).count();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		SectionAnalysis sectionAnalysis = new SectionAnalysis();
 | 
	
		
			
				|  |  | -		sectionAnalysis.setIndex(sectionIndex);
 | 
	
		
			
				|  |  | -		sectionAnalysis.setNoteNum(noteAnalysisList.size());
 | 
	
		
			
				|  |  | -		sectionAnalysis.setIsIngore(ignoreSize == noteAnalysisList.size());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		//判断是否需要评分
 | 
	
		
			
				|  |  | -		MusicXmlSection musicXmlSection = getCurrentMusicSection(null, sectionIndex);
 | 
	
		
			
				|  |  | -		if(noteAnalysisList.size() == musicXmlSection.getNoteNum()){
 | 
	
		
			
				|  |  | -			//取出需要评测的音符
 | 
	
		
			
				|  |  | -			List<NoteAnalysis>  noteList = noteAnalysisList.stream().filter(t -> t.isIgnore() == false).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | -			if(noteList != null && noteList.size() > 0){
 | 
	
		
			
				|  |  | -				score = noteList.stream().mapToInt(t -> t.getScore()).sum() / noteList.size();
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			sectionAnalysis.setDurationTime(noteAnalysisList.stream().mapToDouble(t -> t.getDurationTime()).sum());
 | 
	
		
			
				|  |  | -			sectionAnalysis.setScore(score);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			LOGGER.info("小节评分:{}",sectionAnalysis);
 | 
	
		
			
				|  |  | -			doneSectionAnalysisList.add(sectionAnalysis);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		return score;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public Map<String, Integer> evaluateForMusic() {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		Map<String, Integer> result = new HashMap<String, Integer>();
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		result.put("playTime", (int) doneNoteAnalysisList.stream().mapToDouble(t -> t.getDurationTime()).sum());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		// 取出需要评测的音符
 | 
	
		
			
				|  |  | -		List<NoteAnalysis> noteAnalysisList = doneNoteAnalysisList.stream().filter(t -> t.isIgnore() == false).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (noteAnalysisList != null && noteAnalysisList.size() > 0) {
 | 
	
		
			
				|  |  | -			int intonationScore = 0;
 | 
	
		
			
				|  |  | -			int tempoScore = 0;
 | 
	
		
			
				|  |  | -			int integrityScore = 0;
 | 
	
		
			
				|  |  | -			int socre = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			for (NoteAnalysis note : noteAnalysisList) {
 | 
	
		
			
				|  |  | -				intonationScore += note.getIntonationScore();
 | 
	
		
			
				|  |  | -				tempoScore += note.getTempoScore();
 | 
	
		
			
				|  |  | -				integrityScore += note.getIntegrityScore();
 | 
	
		
			
				|  |  | -				socre += note.getScore();
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			tempoScore = tempoScore / noteAnalysisList.size();
 | 
	
		
			
				|  |  | -			intonationScore = intonationScore / noteAnalysisList.size();
 | 
	
		
			
				|  |  | -			integrityScore = integrityScore / noteAnalysisList.size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			result.put("cadence", tempoScore);
 | 
	
		
			
				|  |  | -			result.put("intonation", intonationScore);
 | 
	
		
			
				|  |  | -			result.put("integrity", integrityScore);
 | 
	
		
			
				|  |  | -	        result.put("recordId", recordId.intValue());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			int score = socre / noteAnalysisList.size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			// 平均得分
 | 
	
		
			
				|  |  | -			if (getMusicXmlBasicInfo(null).getSubjectId() == 23 || getMusicXmlBasicInfo(null).getSubjectId() == 113) {
 | 
	
		
			
				|  |  | -				score = tempoScore;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			result.put("score", score);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		return result;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	public void evaluateForNote(MusicXmlNote musicXmlNote, NoteAnalysis noteAnalysis) {
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
 | 
	
		
			
				|  |  | -		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() + dynamicOffset;
 | 
	
		
			
				|  |  | -		double startTime = musicXmlNote.getTimeStamp() + dynamicOffset;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		//根据完整度取部分有效信号
 | 
	
		
			
				|  |  | -		int elementSize = chunkAnalysisList.size() * (100 - hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())) / 100;
 | 
	
		
			
				|  |  | -		chunkAnalysisList = chunkAnalysisList.subList(0, elementSize);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double playDurationTime = 0;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if (subjectId == 23 || subjectId == 113) {
 | 
	
		
			
				|  |  | -			if (noteAnalysis.getFrequency() == -1) {// 休止符
 | 
	
		
			
				|  |  | -				if (!noteAnalysis.isTempo()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.CADENCE_WRONG);
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.RIGHT);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}else{
 | 
	
		
			
				|  |  | -				int beatTimes = (int) chunkAnalysisList.stream().filter(t -> t.getAmplitude() > hardLevel.getAmplitudeThreshold()).count();
 | 
	
		
			
				|  |  | -				LOGGER.info("Amplitude:{}  beatTimes:{}  Denominator:{}",chunkAnalysisList.stream().map(t -> t.getAmplitude()).collect(Collectors.toList()), beatTimes, musicXmlNote.getDenominator());
 | 
	
		
			
				|  |  | -				if(beatTimes == 0){
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.NOT_PLAY);
 | 
	
		
			
				|  |  | -				}else if (!noteAnalysis.isTempo()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.CADENCE_WRONG);
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.RIGHT);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | -			NotePlayResult notePlayResult = queryNoteFrequency(musicXmlNote, noteAnalysis.getPlayFrequency());
 | 
	
		
			
				|  |  | -			
 | 
	
		
			
				|  |  | -			if (noteAnalysis.getFrequency() == -1) {// 休止符
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				playDurationTime = chunkAnalysisList.stream().filter(t -> t.getFrequency() <= 100).mapToDouble(t -> t.getDurationTime()).sum();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				if (!noteAnalysis.isTempo()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.CADENCE_WRONG);
 | 
	
		
			
				|  |  | -				} else if (playDurationTime * 100 / noteAnalysis.getDurationTime() < hardLevel.getIntegrityRange()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.INTEGRITY_WRONG);
 | 
	
		
			
				|  |  | -				} else if (notePlayResult.getStatus() == false) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.INTONATION_WRONG);
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.RIGHT);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | -				playDurationTime = chunkAnalysisList.stream().filter(t -> t.getFrequency() > 100 && t.getFrequency() < 2000)
 | 
	
		
			
				|  |  | -						.mapToDouble(t -> t.getDurationTime()).sum();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				if (playDurationTime * 100 / noteAnalysis.getDurationTime() < hardLevel.getNotPlayRange()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.NOT_PLAY);
 | 
	
		
			
				|  |  | -				} else if (playDurationTime * 100 / noteAnalysis.getDurationTime() < hardLevel.getIntegrityRange()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.INTEGRITY_WRONG);
 | 
	
		
			
				|  |  | -				} else if (!noteAnalysis.isTempo()) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.CADENCE_WRONG);
 | 
	
		
			
				|  |  | -				} else if (notePlayResult.getStatus() == false) {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.INTONATION_WRONG);
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					noteAnalysis.setMusicalErrorType(NoteErrorType.RIGHT);
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// 计算音分
 | 
	
		
			
				|  |  | -		int tempoScore = 0;
 | 
	
		
			
				|  |  | -		int integrityScore = 0;
 | 
	
		
			
				|  |  | -		int intonationScore = 100 - new BigDecimal(Math.abs(YINPitchDetector.hertzToAbsoluteCent(noteAnalysis.getPlayFrequency())
 | 
	
		
			
				|  |  | -				- YINPitchDetector.hertzToAbsoluteCent(noteAnalysis.getFrequency()))).multiply(new BigDecimal(20)).divide(new BigDecimal(17), BigDecimal.ROUND_UP)
 | 
	
		
			
				|  |  | -				.setScale(0, BigDecimal.ROUND_UP).intValue();
 | 
	
		
			
				|  |  | -		if (intonationScore < 0) {
 | 
	
		
			
				|  |  | -			intonationScore = 0;
 | 
	
		
			
				|  |  | -		} else if (intonationScore > 100) {
 | 
	
		
			
				|  |  | -			intonationScore = 100;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (noteAnalysis.getMusicalErrorType() == NoteErrorType.NOT_PLAY) {
 | 
	
		
			
				|  |  | -			intonationScore = 0;
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if (noteAnalysis.isTempo()) {
 | 
	
		
			
				|  |  | -				tempoScore = 100;
 | 
	
		
			
				|  |  | -				noteAnalysis.setTempoScore(tempoScore);
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			double durationPercent = playDurationTime / noteAnalysis.getDurationTime();
 | 
	
		
			
				|  |  | -			if (durationPercent >= 0.7) {
 | 
	
		
			
				|  |  | -				integrityScore = 100;
 | 
	
		
			
				|  |  | -			} else if (durationPercent < 0.7 && durationPercent >= 0.5) {
 | 
	
		
			
				|  |  | -				integrityScore = 50;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			noteAnalysis.setIntegrityScore(integrityScore);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		noteAnalysis.setIntonationScore(intonationScore);
 | 
	
		
			
				|  |  | -		if (subjectId == 23 || subjectId == 113) {
 | 
	
		
			
				|  |  | -			noteAnalysis.setScore(tempoScore);
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			noteAnalysis.setScore(new BigDecimal(intonationScore + tempoScore + integrityScore).divide(new BigDecimal(3), 2).setScale(0, BigDecimal.ROUND_UP)
 | 
	
		
			
				|  |  | -					.intValue());
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private int computeFrequency(MusicXmlNote musicXmlNote) {
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
 | 
	
		
			
				|  |  | -		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() + dynamicOffset - floatingRange;
 | 
	
		
			
				|  |  | -		double startTime = musicXmlNote.getTimeStamp() + dynamicOffset;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		//根据完整度取部分有效信号
 | 
	
		
			
				|  |  | -		int elementSize = chunkAnalysisList.size() * (100 - hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())) / 100;
 | 
	
		
			
				|  |  | -		chunkAnalysisList = chunkAnalysisList.subList(0, elementSize);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		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());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		List<ChunkAnalysis> chunkList = new ArrayList<ChunkAnalysis>(chunkAnalysisList);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		List<Integer> chunkFrequencyList = chunkList.stream().map(t -> t.getFrequency()).filter(t -> t.doubleValue() > 100 && t.doubleValue() < 2000)
 | 
	
		
			
				|  |  | -				.collect(Collectors.toList());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if (chunkFrequencyList.size() == 0) {
 | 
	
		
			
				|  |  | -			return -1;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		int frequency = (int) (chunkFrequencyList.stream().mapToInt(t -> t).sum() / chunkFrequencyList.size());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return frequency;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	/**
 | 
	
		
			
				|  |  | -	 * 时值范围内有且只有一个音,且不能间断,且在合理范围内需开始演奏
 | 
	
		
			
				|  |  | -	 * 与上一个音相同时,2个音之间需要间断
 | 
	
		
			
				|  |  | -	 * @param musicXmlNote
 | 
	
		
			
				|  |  | -	 * @return
 | 
	
		
			
				|  |  | -	 */
 | 
	
		
			
				|  |  | -	private boolean computeTempoWithFrequency(MusicXmlNote musicXmlNote){
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
 | 
	
		
			
				|  |  | -		double endTime = musicXmlNote.getDuration() + musicXmlNote.getTimeStamp() + dynamicOffset - floatingRange;
 | 
	
		
			
				|  |  | -		double startTime = musicXmlNote.getTimeStamp() + dynamicOffset;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		List<ChunkAnalysis> chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(startTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(endTime)).collect(Collectors.toList());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		//根据完整度取部分有效信号
 | 
	
		
			
				|  |  | -		int elementSize = chunkAnalysisList.size() * (100 - hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())) / 100;
 | 
	
		
			
				|  |  | -		chunkAnalysisList = chunkAnalysisList.subList(0, elementSize);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		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);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if(chunkList.size() == 0){
 | 
	
		
			
				|  |  | -			return false;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		NoteFrequencyRange noteFrequencyRange = null;
 | 
	
		
			
				|  |  | -		ChunkAnalysis chunkAnalysis = null;
 | 
	
		
			
				|  |  | -		boolean tempo = false;
 | 
	
		
			
				|  |  | -		boolean isContinue = true;
 | 
	
		
			
				|  |  | -		int unplayedSize = 0;
 | 
	
		
			
				|  |  | -		int firstPeakIndex = -1;
 | 
	
		
			
				|  |  | -		for (int i = 0; i < chunkList.size(); i++) {
 | 
	
		
			
				|  |  | -			chunkAnalysis = chunkList.get(i);
 | 
	
		
			
				|  |  | -			if (chunkAnalysis != null) {
 | 
	
		
			
				|  |  | -				if (chunkAnalysis.getFrequency() > 100) {
 | 
	
		
			
				|  |  | -					
 | 
	
		
			
				|  |  | -					tempo = true;
 | 
	
		
			
				|  |  | -					if (firstPeakIndex == -1) {
 | 
	
		
			
				|  |  | -						firstPeakIndex = i;
 | 
	
		
			
				|  |  | -						noteFrequencyRange = new NoteFrequencyRange(standardFrequecy, chunkAnalysis.getFrequency());
 | 
	
		
			
				|  |  | -					} else if (noteFrequencyRange.getMinFrequency() > chunkAnalysis.getFrequency()
 | 
	
		
			
				|  |  | -							|| chunkAnalysis.getFrequency() > noteFrequencyRange.getMaxFrequency()) {
 | 
	
		
			
				|  |  | -						// 判断是否是同一个音
 | 
	
		
			
				|  |  | -						tempo = false;
 | 
	
		
			
				|  |  | -						LOGGER.info("节奏错误原因:不是同一个音[{}]:{}-{}", chunkAnalysis.getFrequency(), noteFrequencyRange.getMinFrequency(), noteFrequencyRange.getMaxFrequency());
 | 
	
		
			
				|  |  | -						break;
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -					if (isContinue == false) {
 | 
	
		
			
				|  |  | -						if ((i + 1) / chunkAnalysisList.size() < hardLevel.getIntegrityRange()) {
 | 
	
		
			
				|  |  | -							if (unplayedSize > 0) {
 | 
	
		
			
				|  |  | -								tempo = false;
 | 
	
		
			
				|  |  | -								LOGGER.info("节奏错误原因:信号不连续");
 | 
	
		
			
				|  |  | -								break;
 | 
	
		
			
				|  |  | -							}
 | 
	
		
			
				|  |  | -						}
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -				} else {
 | 
	
		
			
				|  |  | -					if (tempo == true) {
 | 
	
		
			
				|  |  | -						isContinue = false;
 | 
	
		
			
				|  |  | -						unplayedSize++;
 | 
	
		
			
				|  |  | -					}
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if (tempo) {
 | 
	
		
			
				|  |  | -			// 判断进入时间点
 | 
	
		
			
				|  |  | -			if(firstPeakIndex * 100 /chunkAnalysisList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator())){
 | 
	
		
			
				|  |  | -				tempo = false;
 | 
	
		
			
				|  |  | -				LOGGER.info("节奏错误原因:进入时间点太晚");
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			if(tempo){
 | 
	
		
			
				|  |  | -				//判断是否与上一个音延续下来的
 | 
	
		
			
				|  |  | -				if(firstChunkAnalysis.getFrequency() > 100 && lastChunkAnalysis.getFrequency() > 100){
 | 
	
		
			
				|  |  | -					tempo = new NoteFrequencyRange(standardFrequecy, firstChunkAnalysis.getFrequency()).equals(new NoteFrequencyRange(standardFrequecy, lastChunkAnalysis.getFrequency())) == false;
 | 
	
		
			
				|  |  | -					LOGGER.info("节奏错误原因:上一个音延续下来导致的");
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		return tempo;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private boolean computeTempoWithAmplitude2(MusicXmlNote musicXmlNote) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		double floatingRange = musicXmlNote.getDuration() * hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) / 100;
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		double endTime = musicXmlNote.getTimeStamp() + dynamicOffset + floatingRange;
 | 
	
		
			
				|  |  | -		double startTime = musicXmlNote.getTimeStamp() + dynamicOffset - 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 correctedStartTime = queryFirstNoteStartTime(chunkAnalysisList, musicXmlNote);
 | 
	
		
			
				|  |  | -		double correctedEndTime = correctedStartTime + musicXmlNote.getDuration();
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		chunkAnalysisList = totalChunkAnalysisList.stream().filter(t -> Double.doubleToLongBits(t.getStartTime()) >= Double.doubleToLongBits(correctedStartTime) && Double.doubleToLongBits(t.getEndTime()) <= Double.doubleToLongBits(correctedEndTime)).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);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		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());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		// 检测是否有多个波峰
 | 
	
		
			
				|  |  | -		boolean tempo = false;
 | 
	
		
			
				|  |  | -		boolean isContinue = true;
 | 
	
		
			
				|  |  | -		int firstPeakIndex = -1;
 | 
	
		
			
				|  |  | -		int peakSize = 0;
 | 
	
		
			
				|  |  | -		for (int i = 1; i < chunkAmplitudeList.size(); i++) {
 | 
	
		
			
				|  |  | -			if (chunkAmplitudeList.get(i) > hardLevel.getAmplitudeThreshold() && chunkAmplitudeList.get(i) > chunkAmplitudeList.get(i - 1) + 2) {
 | 
	
		
			
				|  |  | -				tempo = true;
 | 
	
		
			
				|  |  | -				if(firstPeakIndex == -1){
 | 
	
		
			
				|  |  | -					firstPeakIndex = i;
 | 
	
		
			
				|  |  | -					peakSize++;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				if (isContinue == false) {
 | 
	
		
			
				|  |  | -					tempo = false;
 | 
	
		
			
				|  |  | -					peakSize++;
 | 
	
		
			
				|  |  | -					break;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | -				if (tempo == true) {
 | 
	
		
			
				|  |  | -					isContinue = false;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if(peakSize == 0){
 | 
	
		
			
				|  |  | -			tempo = lastChunkAnalysis.isPeak();
 | 
	
		
			
				|  |  | -		}else if(peakSize == 1){
 | 
	
		
			
				|  |  | -			tempo = true;
 | 
	
		
			
				|  |  | -		}else{
 | 
	
		
			
				|  |  | -			tempo = false;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if (tempo) {
 | 
	
		
			
				|  |  | -			// 判断进入时间点
 | 
	
		
			
				|  |  | -			if((firstPeakIndex - 1) * 100 /chunkAmplitudeList.size() > hardLevel.getTempoEffectiveRange(musicXmlNote.getDenominator()) * 2){
 | 
	
		
			
				|  |  | -				LOGGER.info("超过范围:{}", (firstPeakIndex - 1) * 100 /chunkAmplitudeList.size());
 | 
	
		
			
				|  |  | -				tempo = false;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		return tempo;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	private double queryFirstNoteStartTime(List<ChunkAnalysis> chunkAnalysisList, MusicXmlNote musicXmlNote) {
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		if(chunkAnalysisList == null || chunkAnalysisList.size() == 0){
 | 
	
		
			
				|  |  | -			return musicXmlNote.getTimeStamp() + dynamicOffset;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		NoteFrequencyRange standardNote = new NoteFrequencyRange(standardFrequecy, musicXmlNote.getFrequency());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		NoteFrequencyRange noteFrequencyRange = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		for (ChunkAnalysis ca : chunkAnalysisList) {
 | 
	
		
			
				|  |  | -			noteFrequencyRange = new NoteFrequencyRange(standardFrequecy, ca.getFrequency());
 | 
	
		
			
				|  |  | -			if (standardNote.equals(noteFrequencyRange)) {
 | 
	
		
			
				|  |  | -				return ca.getStartTime();
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return chunkAnalysisList.get(chunkAnalysisList.size() - 1).getEndTime();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -	public static void main(String[] args) {
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		NoteFrequencyRange range = new NoteFrequencyRange(440, 466);
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -		System.out.println("Min:" + range.getMinFrequency() + "  Max:" + range.getMaxFrequency());
 | 
	
		
			
				|  |  | -		
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	
 | 
	
		
			
				|  |  | -}
 |