|
@@ -169,6 +169,9 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
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){
|
|
|
+ pitch = -1;
|
|
|
+ }
|
|
|
// LOGGER.info("时间:{}, 频率:{}, 分贝:{}, 音分:{}", timeStamp, pitch, silenceDetecor.currentSPL(), cents);
|
|
|
userSoundInfoMap.get(phone).getRecordMeasurePithInfo().add(new MusicPitchDetailDto(timeStamp, pitch, silenceDetecor.currentSPL()));
|
|
|
}));
|
|
@@ -293,7 +296,7 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
//节奏匹配数量
|
|
|
float cadenceNum = 0;
|
|
|
//节奏有效阈值
|
|
|
- float cadenceValidDuty = 0.01f;
|
|
|
+ float cadenceValidDuty = 0.09f;
|
|
|
|
|
|
//完整性误差范围
|
|
|
float integrityRange = 30;
|
|
@@ -323,35 +326,35 @@ 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;
|
|
|
- }
|
|
|
- }
|
|
|
+// 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<>();
|
|
@@ -367,9 +370,6 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
// decibels.add(recordInfo.getDecibel());
|
|
|
measureSoundPitchInfos.add(recordInfo);
|
|
|
compareNum++;
|
|
|
- if(!newMeasure){
|
|
|
- continue;
|
|
|
- }
|
|
|
// LOGGER.info("{}频率({}-{}):{}, {}", recordInfo.getTimeStamp(), startTimeStamp, endTimeStamp, musicXmlInfo.getFrequency(), recordInfo.getFrequency());
|
|
|
//如果在最低有效频率以下则跳过
|
|
|
if(recordInfo.getFrequency()<minValidFrequency&&musicXmlInfo.getFrequency()!=-1){
|
|
@@ -404,6 +404,8 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
boolean ing = false;
|
|
|
//当前分贝
|
|
|
double cd = 0;
|
|
|
+ //分贝变化方向,-1变小,1变大
|
|
|
+ int dcd = -1;
|
|
|
//分贝持续数量
|
|
|
int dnum = 0;
|
|
|
for (MusicPitchDetailDto musicalNotesPitch : measureSoundPitchInfos) {
|
|
@@ -421,13 +423,17 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
}
|
|
|
}
|
|
|
//计算声音大小断层册数
|
|
|
- if(ing && Math.abs(musicalNotesPitch.getDecibel() - cd) > 5){
|
|
|
+ if(ing && Math.abs(musicalNotesPitch.getDecibel() - cd) > 10){
|
|
|
dnum ++;
|
|
|
}
|
|
|
if (dnum > 2){
|
|
|
+ int tdcd = cd > musicalNotesPitch.getDecibel() ? -1 : 1;
|
|
|
cd = musicalNotesPitch.getDecibel();
|
|
|
dnum = 0;
|
|
|
- decibelChangeNum++;
|
|
|
+ if (tdcd != dcd) {
|
|
|
+ decibelChangeNum++;
|
|
|
+ }
|
|
|
+ dcd = tdcd;
|
|
|
}
|
|
|
}
|
|
|
userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) pitch);
|
|
@@ -500,177 +506,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))));
|
|
|
- }
|
|
|
-
|
|
|
- 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))));
|
|
|
+ //计算分数并推送
|
|
|
+ createPushInfo(phone, "measureScore", measureIndex, intonation, cadence, integrity);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -693,7 +530,8 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
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());
|
|
@@ -712,8 +550,8 @@ 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);
|
|
@@ -728,7 +566,13 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
|
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).sendMessage(new TextMessage(JSON.toJSONString(webSocketInfo)));
|
|
|
return webSocketInfo;
|
|
|
}
|
|
|
}
|