|
@@ -2,6 +2,7 @@ package com.ym.mec.teacher.handler;
|
|
|
|
|
|
import be.tarsos.dsp.AudioDispatcher;
|
|
import be.tarsos.dsp.AudioDispatcher;
|
|
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
|
|
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
|
|
|
|
+import be.tarsos.dsp.io.jvm.JVMAudioInputStream;
|
|
import be.tarsos.dsp.pitch.PitchProcessor;
|
|
import be.tarsos.dsp.pitch.PitchProcessor;
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.ym.mec.biz.dal.dto.AudioRecordConfig;
|
|
import com.ym.mec.biz.dal.dto.AudioRecordConfig;
|
|
@@ -9,6 +10,7 @@ import com.ym.mec.biz.dal.dto.MusicPitchDetailDto;
|
|
import com.ym.mec.biz.dal.dto.WavHeader;
|
|
import com.ym.mec.biz.dal.dto.WavHeader;
|
|
import com.ym.mec.biz.dal.dto.WebSocketInfo;
|
|
import com.ym.mec.biz.dal.dto.WebSocketInfo;
|
|
import com.ym.mec.biz.service.SoundSocketService;
|
|
import com.ym.mec.biz.service.SoundSocketService;
|
|
|
|
+import org.apache.commons.lang3.RandomUtils;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
@@ -16,10 +18,13 @@ import org.springframework.web.socket.*;
|
|
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
|
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
|
|
|
|
|
import javax.sound.sampled.AudioFormat;
|
|
import javax.sound.sampled.AudioFormat;
|
|
|
|
+import javax.sound.sampled.AudioInputStream;
|
|
|
|
+import javax.sound.sampled.DataLine;
|
|
|
|
+import javax.sound.sampled.TargetDataLine;
|
|
import java.io.*;
|
|
import java.io.*;
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
-import java.util.Map;
|
|
|
|
|
|
+import java.util.*;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
@@ -38,8 +43,8 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN;
|
|
PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN;
|
|
|
|
|
|
private Map<String, RandomAccessFile> userRandomAccessFileMap = new ConcurrentHashMap<>();
|
|
private Map<String, RandomAccessFile> userRandomAccessFileMap = new ConcurrentHashMap<>();
|
|
- private Map<String, MusicPitchDetailDto> userXmlInfoMap = new ConcurrentHashMap<>();
|
|
|
|
- private Map<String, Double> userRecordTimeMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
+ private Map<String, List<MusicPitchDetailDto>> userXmlInfoMap = new ConcurrentHashMap<>();
|
|
|
|
+ private Map<String, Set<Integer>> userMeasureMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
public WebSocketHandler() {
|
|
public WebSocketHandler() {
|
|
super();
|
|
super();
|
|
@@ -70,10 +75,13 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
commond = webSocketInfo.getHeader().get(SoundSocketService.COMMOND);
|
|
commond = webSocketInfo.getHeader().get(SoundSocketService.COMMOND);
|
|
}
|
|
}
|
|
switch (commond){
|
|
switch (commond){
|
|
|
|
+ case SoundSocketService.MUSIC_XML:
|
|
|
|
+ userXmlInfoMap.put(phone, JSON.parseArray(webSocketInfo.getBody(), MusicPitchDetailDto.class));
|
|
|
|
+ break;
|
|
case SoundSocketService.RECORD_START:
|
|
case SoundSocketService.RECORD_START:
|
|
File file = new File("E:\\Temp\\record"+phone +"-"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +".wav");
|
|
File file = new File("E:\\Temp\\record"+phone +"-"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +".wav");
|
|
userRandomAccessFileMap.put(phone, new RandomAccessFile(file, "rw"));
|
|
userRandomAccessFileMap.put(phone, new RandomAccessFile(file, "rw"));
|
|
- userRecordTimeMap.put(phone, (double) 0);
|
|
|
|
|
|
+ userMeasureMap.put(phone, new HashSet<>());
|
|
break;
|
|
break;
|
|
case SoundSocketService.RECORD_END:
|
|
case SoundSocketService.RECORD_END:
|
|
createHeader(phone);
|
|
createHeader(phone);
|
|
@@ -90,18 +98,31 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
if(userRandomAccessFileMap.containsKey(phone)){
|
|
if(userRandomAccessFileMap.containsKey(phone)){
|
|
userRandomAccessFileMap.get(phone).write(message.getPayload().array());
|
|
userRandomAccessFileMap.get(phone).write(message.getPayload().array());
|
|
}
|
|
}
|
|
- AtomicReference<Double> endTimeStamp = new AtomicReference<>((double) 0);
|
|
|
|
AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), audioFormat, 256, 128);
|
|
AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), audioFormat, 256, 128);
|
|
dispatcher.addAudioProcessor(new PitchProcessor(algo, 44100, 256, (pitchDetectionResult, audioEvent) -> {
|
|
dispatcher.addAudioProcessor(new PitchProcessor(algo, 44100, 256, (pitchDetectionResult, audioEvent) -> {
|
|
- int timeStamp = (int) (audioEvent.getTimeStamp()*1000);
|
|
|
|
|
|
+ double timeStamp = audioEvent.getTimeStamp();
|
|
float pitch = pitchDetectionResult.getPitch();
|
|
float pitch = pitchDetectionResult.getPitch();
|
|
- endTimeStamp.set(audioEvent.getEndTimeStamp());
|
|
|
|
- LOGGER.info("时间:{},频率:{}, endTime:{}", timeStamp, pitch, endTimeStamp.get());
|
|
|
|
|
|
+ LOGGER.info("时间:{},频率:{}", timeStamp, pitch);
|
|
}));
|
|
}));
|
|
dispatcher.run();
|
|
dispatcher.run();
|
|
- LOGGER.info("结束时间:{}", endTimeStamp.get());
|
|
|
|
- double l = endTimeStamp.get() + userRecordTimeMap.get(phone);
|
|
|
|
- userRecordTimeMap.put(phone, l);
|
|
|
|
|
|
+ double recordTime = userRandomAccessFileMap.get(phone).length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000;
|
|
|
|
+ LOGGER.info("时长:{}", recordTime);
|
|
|
|
+ for (MusicPitchDetailDto musicPitchDetailDto : userXmlInfoMap.get(phone)) {
|
|
|
|
+ if(!userMeasureMap.get(phone).contains(musicPitchDetailDto.getMeasureIndex())&&recordTime>musicPitchDetailDto.getTimeStamp()+musicPitchDetailDto.getDuration()){
|
|
|
|
+ WebSocketInfo webSocketInfo = new WebSocketInfo();
|
|
|
|
+ HashMap<String, String> header = new HashMap<>();
|
|
|
|
+ header.put("commond", "measureScore");
|
|
|
|
+ webSocketInfo.setHeader(header);
|
|
|
|
+ Map<String, Double> result = new HashMap<>();
|
|
|
|
+ result.put("score", RandomUtils.nextDouble(0,100));
|
|
|
|
+ result.put("intonation", RandomUtils.nextDouble(0,100));
|
|
|
|
+ result.put("cadence", RandomUtils.nextDouble(0,100));
|
|
|
|
+ result.put("integrity", RandomUtils.nextDouble(0,100));
|
|
|
|
+ webSocketInfo.setBody(JSON.toJSONString(result));
|
|
|
|
+ WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(webSocketInfo)));
|
|
|
|
+ userMeasureMap.get(phone).add(musicPitchDetailDto.getMeasureIndex());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -141,7 +162,6 @@ public class WebSocketHandler extends AbstractWebSocketHandler {
|
|
}
|
|
}
|
|
RandomAccessFile randomAccessFile = userRandomAccessFileMap.get(phone);
|
|
RandomAccessFile randomAccessFile = userRandomAccessFileMap.get(phone);
|
|
randomAccessFile.seek(0);
|
|
randomAccessFile.seek(0);
|
|
- LOGGER.info("音频时长:{}", userRecordTimeMap.get(phone));
|
|
|
|
randomAccessFile.write(new WavHeader(new AudioRecordConfig(), randomAccessFile.length()).toBytes());
|
|
randomAccessFile.write(new WavHeader(new AudioRecordConfig(), randomAccessFile.length()).toBytes());
|
|
randomAccessFile.close();
|
|
randomAccessFile.close();
|
|
userRandomAccessFileMap.remove(phone);
|
|
userRandomAccessFileMap.remove(phone);
|