| 
					
				 | 
			
			
				@@ -3,12 +3,11 @@ package com.ym.mec.biz.handler; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import be.tarsos.dsp.AudioDispatcher; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import be.tarsos.dsp.io.jvm.AudioDispatcherFactory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import be.tarsos.dsp.pitch.PitchProcessor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import be.tarsos.dsp.util.PitchConverter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.alibaba.fastjson.JSON; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.alibaba.fastjson.JSONObject; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import com.ym.mec.biz.dal.dto.MusicPitchDetailDto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import com.ym.mec.biz.dal.dto.SoundCompareHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import com.ym.mec.biz.dal.dto.WavHeader; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import com.ym.mec.biz.dal.dto.WebSocketInfo; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.ym.mec.biz.dal.config.SoundCompareConfig; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.ym.mec.biz.dal.dto.*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.ym.mec.biz.service.SoundSocketService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.ym.mec.biz.service.SysMusicCompareRecordService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import com.ym.mec.common.constant.CommonConstants; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -21,7 +20,6 @@ import org.springframework.util.CollectionUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.web.socket.*; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import org.springframework.web.socket.handler.AbstractWebSocketHandler; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import javax.sound.sampled.AudioFormat; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import java.io.File; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import java.io.IOException; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import java.io.RandomAccessFile; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -41,24 +39,23 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHandler.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    //存储客户端链接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    public static final Map<String, WebSocketSession> WS_CLIENTS = new ConcurrentHashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final BigDecimal oneHundred = new BigDecimal(100); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    //检测偏移时长的最终时间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final int endCheckOffsetTime = 500; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final float simpleRate = 44100; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private int simpleSize = 1024; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @describe 存储客户端链接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public static final Map<String, WebSocketClientDetail> WS_CLIENTS = new ConcurrentHashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private final AudioFormat audioFormat = new AudioFormat(simpleRate, 16, 1, true, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private static final PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private BigDecimal oneHundred = new BigDecimal(100); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private static final String tmpDir = FileUtils.getTempDirectoryPath() + "/soundCompare/"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private final String tmpDir = FileUtils.getTempDirectoryPath() + "/soundCompare/"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    //用户对应评分信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @describe 用户对应评分信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private Map<String, SoundCompareHelper> userSoundInfoMap = new ConcurrentHashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @describe 音频处理参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private SoundCompareConfig soundCompareConfig = new SoundCompareConfig(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Autowired 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private SysMusicCompareRecordService sysMusicCompareRecordService; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -75,7 +72,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public void afterConnectionEstablished(WebSocketSession session) throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         String phone = session.getPrincipal().getName().split(":")[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         LOGGER.info("{}上线", phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        WS_CLIENTS.put(phone, session); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        WS_CLIENTS.put(phone, new WebSocketClientDetail(session, new Date())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         super.afterConnectionEstablished(session); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -99,11 +96,19 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             case SoundSocketService.MUSIC_XML: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 userSoundInfoMap.put(phone, new SoundCompareHelper()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 List<MusicPitchDetailDto> musicXmlInfos = JSON.parseArray(bodyObject.getString("musicXmlInfos"), MusicPitchDetailDto.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                userSoundInfoMap.get(phone).setMusicXmlInfos(musicXmlInfos); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                musicXmlInfos = musicXmlInfos.stream().filter(m->!m.getDontEvaluating()).collect(Collectors.toList()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 userSoundInfoMap.get(phone).setMusicScoreId(bodyObject.getInteger("id")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 userSoundInfoMap.get(phone).setMeasureXmlInfoMap(musicXmlInfos.stream().collect(Collectors.groupingBy(MusicPitchDetailDto::getMeasureIndex))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                musicXmlInfos.forEach(e->userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(e.getMusicalNotesIndex(), e.getFrequency())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 for (Map.Entry<Integer, List<MusicPitchDetailDto>> userMeasureXmlInfoEntry : userSoundInfoMap.get(phone).getMeasureXmlInfoMap().entrySet()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    MusicPitchDetailDto musicPitchDetailDto = userMeasureXmlInfoEntry.getValue().stream().max(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    userSoundInfoMap.get(phone).getMeasureEndTime().put(userMeasureXmlInfoEntry.getKey(), musicPitchDetailDto.getTimeStamp()+musicPitchDetailDto.getDuration()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    MusicPitchDetailDto firstPitch = userMeasureXmlInfoEntry.getValue().stream().min(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    MusicPitchDetailDto lastPitch = userMeasureXmlInfoEntry.getValue().stream().max(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    long dc = userMeasureXmlInfoEntry.getValue().stream().filter(m -> m.getDontEvaluating()).count(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    MusicPitchDetailDto musicPitchDetailDto = new MusicPitchDetailDto(firstPitch.getTimeStamp(), lastPitch.getTimeStamp() + lastPitch.getDuration()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    musicPitchDetailDto.setDuration(musicPitchDetailDto.getEndTimeStamp()-musicPitchDetailDto.getTimeStamp()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    musicPitchDetailDto.setDontEvaluating(dc == userMeasureXmlInfoEntry.getValue().size()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    userSoundInfoMap.get(phone).getMeasureEndTime().put(userMeasureXmlInfoEntry.getKey(), musicPitchDetailDto); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             case SoundSocketService.RECORD_START: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -112,6 +117,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 File file = new File(tmpDir+phone + "_"+ userSoundInfoMap.get(phone).getMusicScoreId() +"_"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +".wav"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 userSoundInfoMap.get(phone).setAccessFile(new RandomAccessFile(file, "rw")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                userSoundInfoMap.get(phone).setRecordFilePath(file.getAbsolutePath()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             case SoundSocketService.RECORD_END: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if(!userSoundInfoMap.containsKey(phone)){ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -119,9 +125,9 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if(!CollectionUtils.isEmpty(userSoundInfoMap.get(phone).getMeasureEndTime())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     Integer lastMeasureIndex = userSoundInfoMap.get(phone).getMeasureEndTime().keySet().stream().min(Integer::compareTo).get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     //如果结束时时长大于某小节,则此小节需要评分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if(recordTime>userSoundInfoMap.get(phone).getMeasureEndTime().get(lastMeasureIndex)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if(recordTime>userSoundInfoMap.get(phone).getMeasureEndTime().get(lastMeasureIndex).getEndTimeStamp()){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         measureCompare(phone, lastMeasureIndex); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         userSoundInfoMap.get(phone).getMeasureEndTime().remove(lastMeasureIndex); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -132,6 +138,12 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             case SoundSocketService.RECORD_CANCEL: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 createHeader(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            case SoundSocketService.PROXY_MESSAGE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                if(bodyObject.containsKey(SoundSocketService.OFFSET_TIME)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                    int offsetTime = bodyObject.getIntValue(SoundSocketService.OFFSET_TIME); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                    calOffsetTime(phone, offsetTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -146,52 +158,36 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(Objects.nonNull(userSoundInfoMap.get(phone).getAccessFile())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             userSoundInfoMap.get(phone).getAccessFile().write(message.getPayload().array()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        List<MusicPitchDetailDto> recordInfo = new ArrayList<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), audioFormat, simpleSize, 128); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        dispatcher.addAudioProcessor(new PitchProcessor(algo, simpleRate, simpleSize, (pitchDetectionResult, audioEvent) -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), soundCompareConfig.audioFormat, soundCompareConfig.simpleSize, soundCompareConfig.overlap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dispatcher.addAudioProcessor(userSoundInfoMap.get(phone).silenceDetector); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dispatcher.addAudioProcessor(new PitchProcessor(soundCompareConfig.algo, soundCompareConfig.simpleRate, soundCompareConfig.simpleSize, (pitchDetectionResult, audioEvent) -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             int timeStamp = (int) (userSoundInfoMap.get(phone).getMeasureStartTime() + audioEvent.getTimeStamp()*1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             float pitch = pitchDetectionResult.getPitch(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//            LOGGER.info("频率:{}, {}", timeStamp, pitch); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            recordInfo.add(new MusicPitchDetailDto(timeStamp, pitch)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(pitch>0 && userSoundInfoMap.get(phone).getOffsetTime() == -1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int preTimeStamp = CollectionUtils.isEmpty(userSoundInfoMap.get(phone).getRecordMeasurePithInfo())?0:userSoundInfoMap.get(phone).getRecordMeasurePithInfo().get(userSoundInfoMap.get(phone).getRecordMeasurePithInfo().size()-1).getTimeStamp(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                calOffsetTime(phone, timeStamp - (timeStamp - preTimeStamp)/2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(userSoundInfoMap.get(phone).silenceDetector.currentSPL()<soundCompareConfig.validDb){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                pitch = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//            LOGGER.info("时间:{}, 频率:{}, 分贝:{}", timeStamp, pitch, silenceDetecor.currentSPL()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userSoundInfoMap.get(phone).getRecordMeasurePithInfo().add(new MusicPitchDetailDto(timeStamp, pitch, userSoundInfoMap.get(phone).silenceDetector.currentSPL())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         dispatcher.run(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(Objects.isNull(userSoundInfoMap.get(phone).getAccessFile())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         userSoundInfoMap.get(phone).setMeasureStartTime(recordTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        userSoundInfoMap.get(phone).getRecordMeasurePithInfo().addAll(recordInfo); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        //如果是第一小节,需要计算出录音与播放不同步导致的空白时间偏移量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(userSoundInfoMap.get(phone).getOffsetTime()<=0&&recordTime<endCheckOffsetTime){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            int hasPitchNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (MusicPitchDetailDto ri : userSoundInfoMap.get(phone).getRecordMeasurePithInfo()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(hasPitchNum<=0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    userSoundInfoMap.get(phone).setOffsetTime(ri.getTimeStamp()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(ri.getFrequency()>0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    hasPitchNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (Map.Entry<Integer, MusicPitchDetailDto> userMeasureEndTimeMapEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(recordTime>(userMeasureEndTimeMapEntry.getValue().getEndTimeStamp())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(userMeasureEndTimeMapEntry.getValue().getDontEvaluating()){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 }else{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    hasPitchNum=0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    measureCompare(phone, userMeasureEndTimeMapEntry.getKey()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(hasPitchNum>=3){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    LOGGER.info("偏移时间:{}", userSoundInfoMap.get(phone).getOffsetTime()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(hasPitchNum<3){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                userSoundInfoMap.get(phone).setOffsetTime(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(userSoundInfoMap.get(phone).getOffsetTime()<=0&&recordTime<endCheckOffsetTime){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (Map.Entry<Integer, Integer> userMeasureEndTimeMapEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if((recordTime - userSoundInfoMap.get(phone).getOffsetTime())>userMeasureEndTimeMapEntry.getValue()){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                measureCompare(phone, userMeasureEndTimeMapEntry.getKey()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 userSoundInfoMap.get(phone).getMeasureEndTime().remove(userMeasureEndTimeMapEntry.getKey()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -214,6 +210,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         exception.printStackTrace(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         LOGGER.info("发生了错误,移除客户端: {}", phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         WS_CLIENTS.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userSoundInfoMap.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         createHeader(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -222,8 +219,9 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         super.afterConnectionClosed(session, status); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         String phone = session.getPrincipal().getName().split(":")[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         LOGGER.info("{}离线", phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        WS_CLIENTS.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         createHeader(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        WS_CLIENTS.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userSoundInfoMap.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @Override 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -232,6 +230,22 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @describe 处理时间偏移 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author Joburgess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date 2021/7/5 0005 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param phone: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param offsetTime: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void calOffsetTime(String phone, int offsetTime){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userSoundInfoMap.get(phone).setOffsetTime(offsetTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (Map.Entry<Integer, MusicPitchDetailDto> musicPitchDetailDtoEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            musicPitchDetailDtoEntry.getValue().setTimeStamp(musicPitchDetailDtoEntry.getValue().getTimeStamp() + offsetTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            musicPitchDetailDtoEntry.getValue().setEndTimeStamp(musicPitchDetailDtoEntry.getValue().getEndTimeStamp() + offsetTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @describe 保存录音数据,并生成wav头信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @author Joburgess 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @date 2021/6/25 0025 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -244,14 +258,13 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(Objects.nonNull(userSoundInfoMap.get(phone).getAccessFile())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             RandomAccessFile randomAccessFile = userSoundInfoMap.get(phone).getAccessFile(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            LOGGER.info("音频时长:{}", randomAccessFile.length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            LOGGER.info("音频时长:{}", randomAccessFile.length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             randomAccessFile.seek(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            randomAccessFile.write(WavHeader.getWaveHeader(randomAccessFile.length(), (long) audioFormat.getFrameRate(), audioFormat.getSampleSizeInBits())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            randomAccessFile.write(WavHeader.getWaveHeader(randomAccessFile.length(), (long) soundCompareConfig.audioFormat.getFrameRate(), soundCompareConfig.audioFormat.getSampleSizeInBits())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             randomAccessFile.close(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             userSoundInfoMap.get(phone).setAccessFile(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 //        userSoundInfoMap.get(phone).setRecordMeasurePithInfo(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        LOGGER.info("评分数据:{}", JSON.toJSONString(userSoundInfoMap.get(phone))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         userSoundInfoMap.remove(phone); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -264,6 +277,10 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @return void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     private void measureCompare(String phone, int measureIndex) throws IOException { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (userSoundInfoMap.get(phone).getOffsetTime() == -1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userSoundInfoMap.get(phone).setOffsetTime(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         //相似度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         BigDecimal intonation = BigDecimal.ZERO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         //节奏 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -272,84 +289,151 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         BigDecimal integrity = BigDecimal.ZERO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //最低有效频率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float minValidFrequency = 20; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //有效音频数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float validNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //音频有效阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float validDuty = 0.5f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //音准匹配数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float intonationNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //音准匹配误差范围 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float intonationErrRange = 15; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //音准有效阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float intonationValidDuty = 0.7f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //音准分数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            float intonationScore = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             //节奏匹配数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             float cadenceNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //节奏匹配误差范围 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float cadenceErrRange = 30; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //节奏有效阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            float cadenceValidDuty = 0.6f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //完整性分数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            float integrityScore = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             int totalCompareNum = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (MusicPitchDetailDto musicXmlInfo : userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                int startTimeStamp = musicXmlInfo.getTimeStamp() + userSoundInfoMap.get(phone).getOffsetTime(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                int endTimeStamp = musicXmlInfo.getTimeStamp()+musicXmlInfo.getDuration() + userSoundInfoMap.get(phone).getOffsetTime(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (int i = 0; i < userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                MusicPitchDetailDto musicXmlInfo = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).get(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int ot5 = (int) (musicXmlInfo.getDuration()*0.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int startTimeStamp = musicXmlInfo.getTimeStamp() + userSoundInfoMap.get(phone).getOffsetTime() + ot5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int endTimeStamp = musicXmlInfo.getTimeStamp()  + userSoundInfoMap.get(phone).getOffsetTime() + musicXmlInfo.getDuration() - ot5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //时间范围内有效音准数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                float recordValidIntonationNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 //时间范围内有效节奏数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 float cadenceValidNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 //时间范围内有效音频数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                float recordValidNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                float integrityValidNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 //时间范围内匹配次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 float compareNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                for (MusicPitchDetailDto recordInfo : userSoundInfoMap.get(phone).getRecordMeasurePithInfo()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                List<MusicPitchDetailDto> measureSoundPitchInfos = new ArrayList<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (int j = 0; j < userSoundInfoMap.get(phone).getRecordMeasurePithInfo().size(); j++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    MusicPitchDetailDto recordInfo = userSoundInfoMap.get(phone).getRecordMeasurePithInfo().get(j); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     //如果在时间范围之外直接跳过 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//                    LOGGER.info("{}频率({}-{}):{}, {}", recordInfo.getTimeStamp(), startTimeStamp, endTimeStamp, musicXmlInfo.getFrequency(), recordInfo.getFrequency()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    measureSoundPitchInfos.add(recordInfo); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     compareNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     //如果在最低有效频率以下则跳过 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if(recordInfo.getFrequency()<minValidFrequency&&musicXmlInfo.getFrequency()!=-1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if(recordInfo.getFrequency()<soundCompareConfig.validFrequency&&musicXmlInfo.getFrequency()!=-1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    recordValidNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    cadenceValidNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     //如果频率差值在节奏误差范围内 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=cadenceErrRange){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        cadenceValidNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    //如果频率差值在音准误差范围内 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=intonationErrRange){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        recordValidIntonationNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=soundCompareConfig.integrityFrequencyRange){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        integrityValidNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //有效音频占比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                float recordValidDuty = recordValidNum/compareNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(recordValidDuty<validDuty){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //非正常频率次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int errPitchNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //分贝变化次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int decibelChangeNum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(CollectionUtils.isEmpty(measureSoundPitchInfos)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }else{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Map<Integer, Long> collect = measureSoundPitchInfos.stream().map(pitch -> (int)pitch.getFrequency()).collect(Collectors.groupingBy(Integer::intValue, Collectors.counting())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //出现次数最多的频率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Integer pitch = collect.entrySet().stream().max(Comparator.comparing(e -> e.getValue())).get().getKey(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //当前频率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double cf = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //频率持续数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int fnum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //是否演奏中 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    boolean ing = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //当前分贝 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double cd = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //分贝变化方向,-1变小,1变大 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int dcd = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //分贝持续数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int dnum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for (MusicPitchDetailDto musicalNotesPitch : measureSoundPitchInfos) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //计算频率断层次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (Math.abs(musicalNotesPitch.getFrequency() - cf) > 20){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            fnum ++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (fnum>=5){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            cf = musicalNotesPitch.getFrequency(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            fnum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if (cf != -1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                errPitchNum ++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                ing = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                cd = musicalNotesPitch.getDecibel(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //计算声音大小断层册数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if(ing && Math.abs(musicalNotesPitch.getDecibel() - cd) > 10){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dnum ++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (dnum > 2){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            int tdcd = cd > musicalNotesPitch.getDecibel() ? -1 : 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            cd = musicalNotesPitch.getDecibel(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dnum = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if (tdcd != dcd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                decibelChangeNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dcd = tdcd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) pitch); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                validNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //有效音高占比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                float intonationDuty = recordValidIntonationNum/compareNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 //有效节奏占比 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 float cadenceDuty = cadenceValidNum/compareNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(intonationDuty>=intonationValidDuty){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    intonationNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //如果频率出现断层或这个音量出现断层,则当前音符节奏无效 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(errPitchNum>=2 || decibelChangeNum>1){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    cadenceDuty = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(cadenceDuty>=cadenceValidDuty){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //节奏 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(cadenceDuty>=soundCompareConfig.cadenceValidDuty){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     cadenceNum++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //音准 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!CollectionUtils.isEmpty(measureSoundPitchInfos)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Double avgPitch = measureSoundPitchInfos.stream().filter(pitch -> Math.abs((pitch.getFrequency()-musicXmlInfo.getFrequency()))<5).collect(Collectors.averagingDouble(pitch -> pitch.getFrequency())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //音分 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double recordCents = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (avgPitch > 0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        recordCents = PitchConverter.hertzToAbsoluteCent(avgPitch); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double cents = PitchConverter.hertzToAbsoluteCent(musicXmlInfo.getFrequency()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double score = 100 - Math.round(Math.abs(cents - recordCents)) + soundCompareConfig.intonationCentsRange; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (score < 0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        score = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }else if(score > 100){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        score = 100; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    intonationScore += score; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    musicXmlInfo.setAvgFrequency(avgPitch.floatValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //完成度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(integrityValidNum>0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    integrityValidNum = integrityValidNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(integrityValidNum > compareNum){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    integrityValidNum = compareNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                float integrityDuty = integrityValidNum/compareNum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                integrityScore += integrityDuty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            intonation = new BigDecimal(intonationNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            cadence = new BigDecimal(cadenceNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            integrity = new BigDecimal(validNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal measureNum = new BigDecimal(totalCompareNum); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            intonation = new BigDecimal(intonationScore).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0, BigDecimal.ROUND_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cadence = new BigDecimal(cadenceNum).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            integrity = new BigDecimal(integrityScore).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } catch (ArithmeticException e){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             LOGGER.info("无musicXml信息"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -372,14 +456,8 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             userSoundInfoMap.get(phone).getUserScoreMap().put("integrity", integrity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        Map<String, BigDecimal> scoreData = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        scoreData.put("intonation", intonation); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        scoreData.put("cadence", cadence); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        scoreData.put("integrity", integrity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        userSoundInfoMap.get(phone).getUserMeasureScoreMap().put(measureIndex, scoreData); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("measureScore", measureIndex, intonation, cadence, integrity)))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //计算分数并推送 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        createPushInfo(phone, "measureScore", measureIndex, intonation, cadence, integrity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /** 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -399,13 +477,16 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if(currentCompareNum>0){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             intonation = userSoundInfoMap.get(phone).getUserScoreMap().get("intonation").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             cadence = userSoundInfoMap.get(phone).getUserScoreMap().get("cadence").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            integrity = new BigDecimal(currentCompareNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_DOWN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            integrity = userSoundInfoMap.get(phone).getUserScoreMap().get("integrity").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("overall", -1, intonation, cadence, integrity)))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //计算分数并推送 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        createPushInfo(phone, "overall", -1, intonation, cadence, integrity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         //存储评分数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        sysMusicCompareRecordService.saveMusicCompareData(phone, userSoundInfoMap.get(phone).getMusicScoreId(), userSoundInfoMap.get(phone).getUserMeasureScoreMap()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        sysMusicCompareRecordService.saveMusicCompareData(phone, userSoundInfoMap.get(phone)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        LOGGER.info("评分数据:{}", JSON.toJSONString(userSoundInfoMap.get(phone))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /** 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -419,22 +500,29 @@ public class WebSocketHandler extends AbstractWebSocketHandler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @param integrity: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * @return com.ym.mec.biz.dal.dto.WebSocketInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    private WebSocketInfo createPushInfo(String command, Integer measureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                         BigDecimal intonation, BigDecimal cadence, BigDecimal integrity){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private WebSocketInfo createPushInfo(String phone, String command, Integer measureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         BigDecimal intonation, BigDecimal cadence, BigDecimal integrity) throws IOException { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         WebSocketInfo webSocketInfo = new WebSocketInfo(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         HashMap<String, String> header = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         header.put("commond", command); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         webSocketInfo.setHeader(header); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         Map<String, Object> result = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        BigDecimal score = intonation.multiply(new BigDecimal(0.5)).add(cadence.multiply(new BigDecimal(0.5))).setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//        BigDecimal score = cadence.setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//        BigDecimal score = intonation.multiply(new BigDecimal(0.5)).add(cadence.multiply(new BigDecimal(0.5))).setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal score = intonation.add(cadence).add(integrity).divide(new BigDecimal(3), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0, BigDecimal.ROUND_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//        BigDecimal score = integrity.setScale(0, BigDecimal.ROUND_HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result.put("score", score); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result.put("intonation", intonation); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result.put("cadence", cadence); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result.put("integrity", integrity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result.put("measureIndex", measureIndex); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         webSocketInfo.setBody(result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userSoundInfoMap.get(phone).getUserMeasureScoreMap().put(measureIndex, result); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         LOGGER.info("小节频分:{}", JSON.toJSONString(webSocketInfo)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //推送结果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        WS_CLIENTS.get(phone).getSession().sendMessage(new TextMessage(JSON.toJSONString(webSocketInfo))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return webSocketInfo; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |