瀏覽代碼

feat:小节评分涉及参数提取

Joburgess 4 年之前
父節點
當前提交
0b735f638e

+ 126 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/config/SoundCompareConfig.java

@@ -0,0 +1,126 @@
+package com.ym.mec.biz.dal.config;
+
+import be.tarsos.dsp.SilenceDetector;
+import be.tarsos.dsp.pitch.PitchProcessor;
+
+import javax.sound.sampled.AudioFormat;
+
+/**
+ * @Author Joburgess
+ * @Date 2021/8/4 0004
+ */
+public class SoundCompareConfig {
+
+    //采样率
+    public float simpleRate = 44100;
+    //采样大小
+    public int simpleSize = 1024;
+    //帧覆盖大小
+    public int overlap = 256;
+
+    //音频解析格式
+    public AudioFormat audioFormat = new AudioFormat(simpleRate, 16, 1, true, false);
+    //音频解析算法
+    public PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN;
+    //分贝检测器
+    public SilenceDetector silenceDetecor = new SilenceDetector();
+
+    //有效分贝大小
+    public int validDb = -70;
+    //有效频率
+    public int validFrequency = 20;
+    //音准前后音分误差范围
+    public int intonationCentsRange = 3;
+    //节奏有效阈值
+    public float cadenceValidDuty = 0.09f;
+    //完整性有效频率误差范围
+    public int integrityFrequencyRange = 30;
+
+    public float getSimpleRate() {
+        return simpleRate;
+    }
+
+    public void setSimpleRate(float simpleRate) {
+        this.simpleRate = simpleRate;
+    }
+
+    public int getSimpleSize() {
+        return simpleSize;
+    }
+
+    public void setSimpleSize(int simpleSize) {
+        this.simpleSize = simpleSize;
+    }
+
+    public int getOverlap() {
+        return overlap;
+    }
+
+    public void setOverlap(int overlap) {
+        this.overlap = overlap;
+    }
+
+    public AudioFormat getAudioFormat() {
+        return audioFormat;
+    }
+
+    public void setAudioFormat(AudioFormat audioFormat) {
+        this.audioFormat = audioFormat;
+    }
+
+    public PitchProcessor.PitchEstimationAlgorithm getAlgo() {
+        return algo;
+    }
+
+    public void setAlgo(PitchProcessor.PitchEstimationAlgorithm algo) {
+        this.algo = algo;
+    }
+
+    public SilenceDetector getSilenceDetecor() {
+        return silenceDetecor;
+    }
+
+    public void setSilenceDetecor(SilenceDetector silenceDetecor) {
+        this.silenceDetecor = silenceDetecor;
+    }
+
+    public int getValidDb() {
+        return validDb;
+    }
+
+    public void setValidDb(int validDb) {
+        this.validDb = validDb;
+    }
+
+    public int getValidFrequency() {
+        return validFrequency;
+    }
+
+    public void setValidFrequency(int validFrequency) {
+        this.validFrequency = validFrequency;
+    }
+
+    public int getIntonationCentsRange() {
+        return intonationCentsRange;
+    }
+
+    public void setIntonationCentsRange(int intonationCentsRange) {
+        this.intonationCentsRange = intonationCentsRange;
+    }
+
+    public float getCadenceValidDuty() {
+        return cadenceValidDuty;
+    }
+
+    public void setCadenceValidDuty(float cadenceValidDuty) {
+        this.cadenceValidDuty = cadenceValidDuty;
+    }
+
+    public int getIntegrityFrequencyRange() {
+        return integrityFrequencyRange;
+    }
+
+    public void setIntegrityFrequencyRange(int integrityFrequencyRange) {
+        this.integrityFrequencyRange = integrityFrequencyRange;
+    }
+}

+ 20 - 78
mec-biz/src/main/java/com/ym/mec/biz/handler/WebSocketHandler.java

@@ -1,12 +1,12 @@
 package com.ym.mec.biz.handler;
 
 import be.tarsos.dsp.AudioDispatcher;
-import be.tarsos.dsp.SilenceDetector;
 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.config.SoundCompareConfig;
 import com.ym.mec.biz.dal.dto.*;
 import com.ym.mec.biz.service.SoundSocketService;
 import com.ym.mec.biz.service.SysMusicCompareRecordService;
@@ -20,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;
@@ -43,20 +42,16 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
     //存储客户端链接
     public static final Map<String, WebSocketClientDetail> WS_CLIENTS = new ConcurrentHashMap<>();
 
-    private final BigDecimal oneHundred = new BigDecimal(100);
-    private final float simpleRate = 44100;
-    private final int simpleSize = 1024;
-    private final int overlap = 256;
-
-    private final AudioFormat audioFormat = new AudioFormat(simpleRate, 16, 1, true, false);
-    private static final PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN;
-    private final SilenceDetector silenceDetecor = new SilenceDetector();
+    private BigDecimal oneHundred = new BigDecimal(100);
 
     private final String tmpDir = FileUtils.getTempDirectoryPath() + "/soundCompare/";
 
     //用户对应评分信息
     private Map<String, SoundCompareHelper> userSoundInfoMap = new ConcurrentHashMap<>();
 
+    //音频处理参数
+    private SoundCompareConfig soundCompareConfig = new SoundCompareConfig();
+
     @Autowired
     private SysMusicCompareRecordService sysMusicCompareRecordService;
 
@@ -125,7 +120,7 @@ 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).getEndTimeStamp()){
                         measureCompare(phone, lastMeasureIndex);
@@ -159,31 +154,30 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
             userSoundInfoMap.get(phone).getAccessFile().write(message.getPayload().array());
         }
 
-        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), audioFormat, simpleSize, overlap);
-        dispatcher.addAudioProcessor(silenceDetecor);
-        dispatcher.addAudioProcessor(new PitchProcessor(algo, simpleRate, simpleSize, (pitchDetectionResult, audioEvent) -> {
+        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), soundCompareConfig.audioFormat, soundCompareConfig.simpleSize, soundCompareConfig.overlap);
+        dispatcher.addAudioProcessor(soundCompareConfig.silenceDetecor);
+        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();
             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(silenceDetecor.currentSPL()<-70){
+            if(soundCompareConfig.silenceDetecor.currentSPL()<soundCompareConfig.validDb){
                 pitch = -1;
             }
 //            LOGGER.info("时间:{}, 频率:{}, 分贝:{}", timeStamp, pitch, silenceDetecor.currentSPL());
-            userSoundInfoMap.get(phone).getRecordMeasurePithInfo().add(new MusicPitchDetailDto(timeStamp, pitch, silenceDetecor.currentSPL()));
+            userSoundInfoMap.get(phone).getRecordMeasurePithInfo().add(new MusicPitchDetailDto(timeStamp, pitch, soundCompareConfig.silenceDetecor.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);
         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)){
+            if(recordTime>(userMeasureEndTimeMapEntry.getValue().getEndTimeStamp())){
                 if(userMeasureEndTimeMapEntry.getValue().getDontEvaluating()){
                     continue;
                 }else{
@@ -259,9 +253,9 @@ 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);
         }
@@ -290,23 +284,15 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
         BigDecimal integrity = BigDecimal.ZERO;
 
         try {
-            //最低有效频率
-            float minValidFrequency = 20;
-
             //音准分数
             float intonationScore = 0;
 
             //节奏匹配数量
             float cadenceNum = 0;
-            //节奏有效阈值
-            float cadenceValidDuty = 0.09f;
 
-            //完整性误差范围
-            float integrityRange = 30;
             //完整性分数
             float integrityScore = 0;
 
-
             int totalCompareNum = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size();
 
             for (int i = 0; i < userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size(); i++) {
@@ -316,12 +302,6 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                 int startTimeStamp = musicXmlInfo.getTimeStamp() + userSoundInfoMap.get(phone).getOffsetTime() + ot5;
                 int endTimeStamp = musicXmlInfo.getTimeStamp()  + userSoundInfoMap.get(phone).getOffsetTime() + musicXmlInfo.getDuration() - ot5;
 
-                int preMeasureEndTimeStamp = startTimeStamp;
-                List<MusicPitchDetailDto> ms = userSoundInfoMap.get(phone).getMusicXmlInfos().stream().filter(m -> m.getMusicalNotesIndex() == musicXmlInfo.getMusicalNotesIndex() - 1).collect(Collectors.toList());
-                if(!CollectionUtils.isEmpty(ms)){
-                    preMeasureEndTimeStamp = ms.get(0).getEndTimeStamp() + userSoundInfoMap.get(phone).getOffsetTime();
-                }
-
                 //时间范围内有效节奏数量
                 float cadenceValidNum = 0;
                 //时间范围内有效音频数量
@@ -329,38 +309,6 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                 //时间范围内匹配次数
                 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);
-//                }
-//                if(userSoundInfoMap.get(phone).getMusicalNotePitchMap().get(musicXmlInfo.getMusicalNotesIndex())==-1){
-//                    newMeasure = true;
-//                }
-//                int newNum = 0;
-//
-//                for (MusicPitchDetailDto recordInfo : userSoundInfoMap.get(phone).getRecordMeasurePithInfo()) {
-//                    if(musicXmlInfo.getMusicalNotesIndex()==0){
-//                        newMeasure = true;
-//                    }
-//                    if(newMeasure){
-//                        break;
-//                    }
-//                    if(recordInfo.getTimeStamp()<preMeasureEndTimeStamp||recordInfo.getTimeStamp()>startTimeStamp){
-//                        continue;
-//                    }
-//                    if(Math.abs(recordInfo.getFrequency()-preMusicalNotesPitch)>10){
-//                        newNum++;
-//                    }else{
-//                        newNum = 0;
-//                    }
-//                    if(newNum>=2){
-//                        newMeasure = true;
-//                    }
-//                }
-
-//                List<Float> musicalNotesPitchs = new ArrayList<>();
-//                List<Float> decibels = new ArrayList<>();
                 List<MusicPitchDetailDto> measureSoundPitchInfos = new ArrayList<>();
 
                 for (int j = 0; j < userSoundInfoMap.get(phone).getRecordMeasurePithInfo().size(); j++) {
@@ -369,21 +317,15 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                     if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
                         continue;
                     }
-//                    musicalNotesPitchs.add(recordInfo.getFrequency());
-//                    decibels.add(recordInfo.getDecibel());
                     measureSoundPitchInfos.add(recordInfo);
                     compareNum++;
-//                    LOGGER.info("{}频率({}-{}):{}, {}", recordInfo.getTimeStamp(), startTimeStamp, endTimeStamp, musicXmlInfo.getFrequency(), recordInfo.getFrequency());
                     //如果在最低有效频率以下则跳过
-                    if(recordInfo.getFrequency()<minValidFrequency&&musicXmlInfo.getFrequency()!=-1){
+                    if(recordInfo.getFrequency()<soundCompareConfig.validFrequency&&musicXmlInfo.getFrequency()!=-1){
                         continue;
                     }
                     cadenceValidNum++;
-                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
-                        continue;
-                    }
                     //如果频率差值在节奏误差范围内
-                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=integrityRange){
+                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=soundCompareConfig.integrityFrequencyRange){
                         integrityValidNum++;
                     }
                 }
@@ -449,7 +391,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                     cadenceDuty = 0;
                 }
                 //节奏
-                if(cadenceDuty>=cadenceValidDuty){
+                if(cadenceDuty>=soundCompareConfig.cadenceValidDuty){
                     cadenceNum++;
                 }
                 //音准
@@ -461,7 +403,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                         recordCents = PitchConverter.hertzToAbsoluteCent(avgPitch);
                     }
                     double cents = PitchConverter.hertzToAbsoluteCent(musicXmlInfo.getFrequency());
-                    double score = 100 - Math.round(Math.abs(cents - recordCents)) + 3;
+                    double score = 100 - Math.round(Math.abs(cents - recordCents)) + soundCompareConfig.intonationCentsRange;
                     if (score < 0){
                         score = 0;
                     }else if(score > 100){
@@ -472,7 +414,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
                 }
                 //完成度
                 if(integrityValidNum>0){
-                    integrityValidNum = integrityValidNum + (float) (compareNum * 0.05);
+                    integrityValidNum = integrityValidNum;
                 }
                 if(integrityValidNum > compareNum){
                     integrityValidNum = compareNum;