Browse Source

Merge remote-tracking branch 'origin/master'

zouxuan 4 years ago
parent
commit
0506ea80d1

+ 38 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/MusicPitchDetailDto.java

@@ -11,6 +11,9 @@ public class MusicPitchDetailDto {
     @ApiModelProperty("时间戳ms")
     private int timeStamp;
 
+    @ApiModelProperty("结束时间戳")
+    private int endTimeStamp;
+
     @ApiModelProperty("持续时长ms")
     private int duration;
 
@@ -20,6 +23,36 @@ public class MusicPitchDetailDto {
     @ApiModelProperty("小节数")
     private int measureIndex;
 
+    @ApiModelProperty("音符数")
+    private int musicalNotesIndex;
+
+    @ApiModelProperty("不需要评分")
+    private Boolean dontEvaluating;
+
+    public Boolean getDontEvaluating() {
+        return dontEvaluating;
+    }
+
+    public void setDontEvaluating(Boolean dontEvaluating) {
+        this.dontEvaluating = dontEvaluating;
+    }
+
+    public int getMusicalNotesIndex() {
+        return musicalNotesIndex;
+    }
+
+    public void setMusicalNotesIndex(int musicalNotesIndex) {
+        this.musicalNotesIndex = musicalNotesIndex;
+    }
+
+    public int getEndTimeStamp() {
+        return endTimeStamp;
+    }
+
+    public void setEndTimeStamp(int endTimeStamp) {
+        this.endTimeStamp = endTimeStamp;
+    }
+
     public MusicPitchDetailDto() {
     }
 
@@ -28,6 +61,11 @@ public class MusicPitchDetailDto {
         this.frequency = frequency;
     }
 
+    public MusicPitchDetailDto(int timeStamp, int endTimeStamp) {
+        this.timeStamp = timeStamp;
+        this.endTimeStamp = endTimeStamp;
+    }
+
     public MusicPitchDetailDto(int timeStamp, int duration, float frequency) {
         this.timeStamp = timeStamp;
         this.duration = duration;

+ 24 - 3
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/SoundCompareHelper.java

@@ -25,7 +25,7 @@ public class SoundCompareHelper {
     private Map<Integer, List<MusicPitchDetailDto>> measureXmlInfoMap = new HashMap<>();
 
     @ApiModelProperty(value = "小节结束时间字典")
-    private Map<Integer, Integer> measureEndTime = new HashMap<>();
+    private Map<Integer, MusicPitchDetailDto> measureEndTime = new HashMap<>();
 
     @ApiModelProperty(value = "录音音频信息")
     private List<MusicPitchDetailDto> recordMeasurePithInfo = new ArrayList<>();
@@ -35,9 +35,30 @@ public class SoundCompareHelper {
 
     private Map<Integer, Map<String, BigDecimal>> userMeasureScoreMap = new HashMap<>();
 
+    @ApiModelProperty(value = "音符频率字典")
+    private Map<Integer, Float> musicalNotePitchMap = new HashMap<>();
+
     @ApiModelProperty(value = "偏移时间量,解决客户端录音播放不同步导致的声音留白")
     private int offsetTime;
 
+    private byte[] preDataArray = new byte[0];
+
+    public Map<Integer, Float> getMusicalNotePitchMap() {
+        return musicalNotePitchMap;
+    }
+
+    public void setMusicalNotePitchMap(Map<Integer, Float> musicalNotePitchMap) {
+        this.musicalNotePitchMap = musicalNotePitchMap;
+    }
+
+    public byte[] getPreDataArray() {
+        return preDataArray;
+    }
+
+    public void setPreDataArray(byte[] preDataArray) {
+        this.preDataArray = preDataArray;
+    }
+
     public int getOffsetTime() {
         return offsetTime;
     }
@@ -78,11 +99,11 @@ public class SoundCompareHelper {
         this.measureXmlInfoMap = measureXmlInfoMap;
     }
 
-    public Map<Integer, Integer> getMeasureEndTime() {
+    public Map<Integer, MusicPitchDetailDto> getMeasureEndTime() {
         return measureEndTime;
     }
 
-    public void setMeasureEndTime(Map<Integer, Integer> measureEndTime) {
+    public void setMeasureEndTime(Map<Integer, MusicPitchDetailDto> measureEndTime) {
         this.measureEndTime = measureEndTime;
     }
 

+ 276 - 58
mec-biz/src/main/java/com/ym/mec/biz/handler/WebSocketHandler.java

@@ -22,6 +22,7 @@ import org.springframework.web.socket.*;
 import org.springframework.web.socket.handler.AbstractWebSocketHandler;
 
 import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.UnsupportedAudioFileException;
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
@@ -99,11 +100,16 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
             case SoundSocketService.MUSIC_XML:
                 userSoundInfoMap.put(phone, new SoundCompareHelper());
                 List<MusicPitchDetailDto> musicXmlInfos = JSON.parseArray(bodyObject.getString("musicXmlInfos"), MusicPitchDetailDto.class);
+                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();
+                    MusicPitchDetailDto musicPitchDetailDto = new MusicPitchDetailDto(firstPitch.getTimeStamp(), lastPitch.getTimeStamp() + lastPitch.getDuration());
+                    musicPitchDetailDto.setDuration(musicPitchDetailDto.getEndTimeStamp()-musicPitchDetailDto.getTimeStamp());
+                    userSoundInfoMap.get(phone).getMeasureEndTime().put(userMeasureXmlInfoEntry.getKey(), musicPitchDetailDto);
                 }
                 break;
             case SoundSocketService.RECORD_START:
@@ -121,7 +127,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                     Integer lastMeasureIndex = userSoundInfoMap.get(phone).getMeasureEndTime().keySet().stream().min(Integer::compareTo).get();
                     double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(audioFormat.getFrameSize()*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,6 +158,7 @@ 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) -> {
@@ -160,38 +173,14 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
         }
 
         double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(audioFormat.getFrameSize()*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++;
-                }else{
-                    hasPitchNum=0;
-                }
-                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()){
+        for (Map.Entry<Integer, MusicPitchDetailDto> userMeasureEndTimeMapEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) {
+            int ot = (int) (userMeasureEndTimeMapEntry.getValue().getDuration()*0.1);
+            if(recordTime>(userMeasureEndTimeMapEntry.getValue().getEndTimeStamp()+ot)){
+//                LOGGER.info("频分开始{}:{}, {}, {}", recordTime, userSoundInfoMap.get(phone).getAccessFile().length(), ot, JSON.toJSONString(userMeasureEndTimeMapEntry.getValue()));
                 measureCompare(phone, userMeasureEndTimeMapEntry.getKey());
+//                measureCompare2(phone, userMeasureEndTimeMapEntry.getValue());
                 userSoundInfoMap.get(phone).getMeasureEndTime().remove(userMeasureEndTimeMapEntry.getKey());
                 break;
             }
@@ -232,6 +221,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
@@ -275,81 +280,130 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
             //最低有效频率
             float minValidFrequency = 20;
 
-            //有效音频数量
-            float validNum = 0;
-            //音频有效阈值
-            float validDuty = 0.5f;
-
             //音准匹配数量
             float intonationNum = 0;
             //音准匹配误差范围
             float intonationErrRange = 15;
             //音准有效阈值
-            float intonationValidDuty = 0.7f;
+            float intonationValidDuty = 0.2f;
 
             //节奏匹配数量
             float cadenceNum = 0;
             //节奏匹配误差范围
             float cadenceErrRange = 30;
             //节奏有效阈值
-            float cadenceValidDuty = 0.6f;
+            float cadenceValidDuty = 0.2f;
+
+            //完整性数量
+            float integrityNum = 0;
+            //完整性误差范围
+            float integrityRange = 30;
+            //完整性有效阈值
+            float integrityValidDuty = 0.5f;
 
             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() - ot5;
+                int endTimeStamp = musicXmlInfo.getTimeStamp() + musicXmlInfo.getDuration() + ot5;
 
                 //时间范围内有效音准数量
                 float recordValidIntonationNum = 0;
                 //时间范围内有效节奏数量
                 float cadenceValidNum = 0;
                 //时间范围内有效音频数量
-                float recordValidNum = 0;
+                float integrityValidNum = 0;
                 //时间范围内匹配次数
                 float compareNum = 0;
+
+                boolean newMeasure = false;
+                float preMusicalNotesPitch = 0;
+                if(userSoundInfoMap.get(phone).getMusicalNotePitchMap().containsKey(musicXmlInfo.getMusicalNotesIndex()-1)){
+                    preMusicalNotesPitch = userSoundInfoMap.get(phone).getMusicalNotePitchMap().get(musicXmlInfo.getMusicalNotesIndex()-1);
+                }
+                int newNum = 0;
+
                 for (MusicPitchDetailDto recordInfo : userSoundInfoMap.get(phone).getRecordMeasurePithInfo()) {
+                    if(musicXmlInfo.getMusicalNotesIndex()==0){
+                        newMeasure = true;
+                    }
+                    if(newMeasure){
+                        break;
+                    }
+                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
+                        continue;
+                    }
+                    if(Math.abs(recordInfo.getFrequency()-preMusicalNotesPitch)>10){
+                        newNum++;
+                    }
+                    if(newNum>=2){
+                        newMeasure = true;
+                    }
+                }
+
+                List<Integer> musicalNotesPitchs = 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;
                     }
+                    musicalNotesPitchs.add((int) recordInfo.getFrequency());
+                    if(!newMeasure){
+                        continue;
+                    }
 //                    LOGGER.info("{}频率({}-{}):{}, {}", recordInfo.getTimeStamp(), startTimeStamp, endTimeStamp, musicXmlInfo.getFrequency(), recordInfo.getFrequency());
                     compareNum++;
                     //如果在最低有效频率以下则跳过
                     if(recordInfo.getFrequency()<minValidFrequency&&musicXmlInfo.getFrequency()!=-1){
                         continue;
                     }
-                    recordValidNum++;
+                    cadenceValidNum++;
+                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
+                        continue;
+                    }
                     //如果频率差值在节奏误差范围内
-                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=cadenceErrRange){
-                        cadenceValidNum++;
+                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=integrityRange){
+                        integrityValidNum++;
                     }
                     //如果频率差值在音准误差范围内
                     if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=intonationErrRange){
                         recordValidIntonationNum++;
                     }
                 }
-                //有效音频占比
-                float recordValidDuty = recordValidNum/compareNum;
-                if(recordValidDuty<validDuty){
-                    continue;
+
+                if(CollectionUtils.isEmpty(musicalNotesPitchs)){
+                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) 0);
+                }else{
+                    Map<Integer, Long> collect = musicalNotesPitchs.stream().collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
+                    Integer pitch = collect.entrySet().stream().max(Comparator.comparing(e -> e.getValue())).get().getKey();
+                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) pitch);
                 }
-                validNum++;
+
+                //有效音频占比
+                float integrityDuty = integrityValidNum/compareNum;
                 //有效音高占比
                 float intonationDuty = recordValidIntonationNum/compareNum;
                 //有效节奏占比
                 float cadenceDuty = cadenceValidNum/compareNum;
-                if(intonationDuty>=intonationValidDuty){
-                    intonationNum++;
-                }
+                //节奏
                 if(cadenceDuty>=cadenceValidDuty){
                     cadenceNum++;
+                    if(intonationDuty>=intonationValidDuty){
+                        intonationNum++;
+                    }
+                    if(integrityDuty>=integrityValidDuty){
+                        integrityNum++;
+                    }
                 }
             }
 
             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);
+            integrity = new BigDecimal(integrityNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP);
         } catch (ArithmeticException e){
             LOGGER.info("无musicXml信息");
         }
@@ -382,6 +436,169 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
         WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("measureScore", measureIndex, intonation, cadence, integrity))));
     }
 
+    private void measureCompare2(String phone, MusicPitchDetailDto measureTimeInfo) throws IOException, UnsupportedAudioFileException {
+        //小节总时长
+        double measureTime = measureTimeInfo.getEndTimeStamp()-measureTimeInfo.getTimeStamp();
+        double ot = measureTime * 0.1;
+        measureTime += ot;
+        //小节时长占用字节数
+        int measureByteNum = (int) (measureTime/1000*(audioFormat.getFrameSize()*audioFormat.getFrameRate()));
+
+        List<MusicPitchDetailDto> recordInfo = new ArrayList<>();
+        byte[] bytes = new byte[measureByteNum];
+        long startOffset = (userSoundInfoMap.get(phone).getAccessFile().length()-measureByteNum);
+        userSoundInfoMap.get(phone).getAccessFile().seek(startOffset);
+//        userSoundInfoMap.get(phone).getAccessFile().seek(0);
+        userSoundInfoMap.get(phone).getAccessFile().readFully(bytes);
+
+        userSoundInfoMap.get(phone).getAccessFile().seek(userSoundInfoMap.get(phone).getAccessFile().length());
+
+        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(bytes, audioFormat, simpleSize, 128);
+        dispatcher.addAudioProcessor(new PitchProcessor(algo, simpleRate, simpleSize, (pitchDetectionResult, audioEvent) -> {
+            int timeStamp = (int) (measureTimeInfo.getTimeStamp() - (ot>measureTimeInfo.getTimeStamp()?0:ot) + audioEvent.getTimeStamp()*1000);
+            float pitch = pitchDetectionResult.getPitch();
+            recordInfo.add(new MusicPitchDetailDto(timeStamp, pitch));
+        }));
+        dispatcher.run();
+        userSoundInfoMap.get(phone).getRecordMeasurePithInfo().addAll(recordInfo);
+        LOGGER.info("小节评分频率{}:{}", measureTimeInfo.getMeasureIndex(), JSON.toJSONString(recordInfo));
+        scoreCal(phone, measureTimeInfo, recordInfo);
+    }
+
+    private void scoreCal(String phone, MusicPitchDetailDto measureTimeInfo, List<MusicPitchDetailDto> recordPitchDetails) throws IOException {
+        //相似度
+        BigDecimal intonation = BigDecimal.ZERO;
+        //节奏
+        BigDecimal cadence = BigDecimal.ZERO;
+        //完整度
+        BigDecimal integrity = BigDecimal.ZERO;
+
+        try {
+            //最低有效频率
+            float minValidFrequency = 20;
+
+            //音准匹配数量
+            float intonationNum = 0;
+            //音准匹配误差范围
+            float intonationErrRange = 15;
+            //音准有效阈值
+            float intonationValidDuty = 0.1f;
+
+            //节奏匹配数量
+            float cadenceNum = 0;
+            //节奏有效阈值
+            float cadenceValidDuty = 0.1f;
+
+            //完整性数量
+            float integrityNum = 0;
+            //完整性误差范围
+            float integrityRange = 30;
+            //完整性有效阈值
+            float integrityValidDuty = 0.5f;
+
+            int totalCompareNum = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureTimeInfo.getMeasureIndex()).size();
+
+            for (MusicPitchDetailDto musicXmlInfo : userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureTimeInfo.getMeasureIndex())) {
+                int ot5 = (int) (musicXmlInfo.getDuration()*0.1);
+                int startTimeStamp = musicXmlInfo.getTimeStamp() - ot5;
+                int endTimeStamp = musicXmlInfo.getTimeStamp() + ot5;
+
+                //时间范围内有效音准数量
+                float recordValidIntonationNum = 0;
+                //时间范围内有效节奏数量
+                float cadenceValidNum = 0;
+                //时间范围内有效音频数量
+                float integrityValidNum = 0;
+                //时间范围内匹配次数
+                float compareNum = 0;
+                int faultNum = 0;
+                for (int i = 0; i < recordPitchDetails.size(); i++) {
+                    MusicPitchDetailDto recordInfo = recordPitchDetails.get(i);
+                    if(recordInfo.getTimeStamp()>(startTimeStamp-ot5)&&Math.abs((recordInfo.getFrequency()-musicXmlInfo.getFrequency()))>20){
+                        faultNum++;
+                    }else{
+                        if(faultNum<6)
+                            faultNum = 0;
+                    }
+                    if(faultNum<6){
+                        continue;
+                    }
+                    //如果在时间范围之外直接跳过
+                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
+                        continue;
+                    }
+//                    LOGGER.info("{}频率({}-{}):{}, {}", recordInfo.getTimeStamp(), startTimeStamp, endTimeStamp, musicXmlInfo.getFrequency(), recordInfo.getFrequency());
+                    compareNum++;
+                    //如果在最低有效频率以下则跳过
+                    if(recordInfo.getFrequency()<minValidFrequency&&musicXmlInfo.getFrequency()!=-1){
+                        continue;
+                    }
+                    cadenceValidNum++;
+                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
+                        continue;
+                    }
+                    //如果频率差值在节奏误差范围内
+                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=integrityRange){
+                        integrityValidNum++;
+                    }
+                    //如果频率差值在音准误差范围内
+                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=intonationErrRange){
+                        recordValidIntonationNum++;
+                    }
+                }
+                //有效音频占比
+                float integrityDuty = integrityValidNum/compareNum;
+                //有效音高占比
+                float intonationDuty = recordValidIntonationNum/compareNum;
+                //有效节奏占比
+                float cadenceDuty = cadenceValidNum/compareNum;
+                //节奏
+                if(cadenceDuty>=cadenceValidDuty){
+                    cadenceNum++;
+                    if(intonationDuty>=intonationValidDuty){
+                        intonationNum++;
+                    }
+                    if(integrityDuty>=integrityValidDuty){
+                        integrityNum++;
+                    }
+                }
+            }
+
+            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(integrityNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP);
+        } catch (ArithmeticException e){
+            LOGGER.info("无musicXml信息");
+        }
+
+        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("intonation")){
+            userSoundInfoMap.get(phone).getUserScoreMap().put("intonation", intonation.add(userSoundInfoMap.get(phone).getUserScoreMap().get("intonation")));
+        }else{
+            userSoundInfoMap.get(phone).getUserScoreMap().put("intonation", intonation);
+        }
+
+        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("cadence")){
+            userSoundInfoMap.get(phone).getUserScoreMap().put("cadence", cadence.add(userSoundInfoMap.get(phone).getUserScoreMap().get("cadence")));
+        }else{
+            userSoundInfoMap.get(phone).getUserScoreMap().put("cadence", cadence);
+        }
+
+        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("integrity")){
+            userSoundInfoMap.get(phone).getUserScoreMap().put("integrity", integrity.add(userSoundInfoMap.get(phone).getUserScoreMap().get("integrity")));
+        }else{
+            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(measureTimeInfo.getMeasureIndex(), scoreData);
+
+        WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("measureScore", measureTimeInfo.getMeasureIndex(), intonation, cadence, integrity))));
+    }
+
     /**
      * @describe 计算最终评分
      * @author Joburgess
@@ -399,7 +616,7 @@ 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))));
@@ -426,8 +643,9 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
         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_HALF_UP);
+//        BigDecimal score = intonation.setScale(0, BigDecimal.ROUND_HALF_UP);
         result.put("score", score);
         result.put("intonation", intonation);
         result.put("cadence", cadence);

+ 2 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/SoundSocketService.java

@@ -11,5 +11,7 @@ public interface SoundSocketService {
     String RECORD_START = "recordStart";
     String RECORD_END = "recordEnd";
     String RECORD_CANCEL = "recordCancel";
+    String PROXY_MESSAGE = "proxyMessage";
+    String OFFSET_TIME = "offsetTime";
 
 }