yonge 3 роки тому
батько
коміт
e64efdb817

+ 1 - 1
audio-analysis/src/main/java/com/yonge/audio/utils/ArrayUtil.java

@@ -89,7 +89,7 @@ public class ArrayUtil {
 
 	public static void main(String[] args) {
 		byte[] b1 = { 1, 2, 3, 4, 5 };
-		byte[] b2 = { 3, 2, 1 };
+		//byte[] b2 = { 3, 2, 1 };
 		byte[] r = extractByte(b1, 0, 4);
 		for (int i = 0; i < r.length; i++) {
 			System.out.println(r[i]);

+ 5 - 3
audio-analysis/src/main/java/com/yonge/nettty/dto/UserChannelContext.java

@@ -80,9 +80,11 @@ public class UserChannelContext {
 				beatByteLength -= datas.length;
 				return new byte[0];
 			}
-			byte[] data = ArrayUtil.extractByte(datas, beatByteLength, datas.length - 1);
+			if(beatByteLength % 2 != 0){
+				beatByteLength++;
+			}
+			datas = ArrayUtil.extractByte(datas, beatByteLength, datas.length - 1);
 			beatByteLength = 0;
-			return data;
 		}
 		return datas;
 	}
@@ -244,7 +246,7 @@ public class UserChannelContext {
 		return evaluatingSectionIndex;
 	}
 
-	public void handle1(float[] samples, AudioFormat audioFormat){
+	public void handle(float[] samples, AudioFormat audioFormat){
 		
 		YINPitchDetector frequencyDetector = new YINPitchDetector(samples.length , audioFormat.getSampleRate());
 

+ 2 - 2
audio-analysis/src/main/java/com/yonge/netty/server/NettyServer.java

@@ -26,8 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 
 import com.yonge.netty.server.handler.NettyServerHandler;
-import com.yonge.netty.server.messagehandler.BinaryWebSocketFrameHandler;
-import com.yonge.netty.server.messagehandler.TextWebSocketHandler;
+import com.yonge.netty.server.handler.message.BinaryWebSocketFrameHandler;
+import com.yonge.netty.server.handler.message.TextWebSocketHandler;
 
 @Configuration
 public class NettyServer {

+ 9 - 0
audio-analysis/src/main/java/com/yonge/netty/server/handler/ChannelContextConstants.java

@@ -0,0 +1,9 @@
+package com.yonge.netty.server.handler;
+
+import io.netty.util.AttributeKey;
+
+public class ChannelContextConstants {
+
+	public static final AttributeKey<String> CHANNEL_ATTR_KEY_ACTION = AttributeKey.newInstance("action");
+	
+}

+ 1 - 1
audio-analysis/src/main/java/com/yonge/netty/server/NettyChannelManager.java → audio-analysis/src/main/java/com/yonge/netty/server/handler/NettyChannelManager.java

@@ -1,4 +1,4 @@
-package com.yonge.netty.server;
+package com.yonge.netty.server.handler;
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelId;

+ 0 - 2
audio-analysis/src/main/java/com/yonge/netty/server/handler/NettyServerHandler.java

@@ -14,8 +14,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 import org.springframework.stereotype.Component;
 
-import com.yonge.netty.server.NettyChannelManager;
-
 @Component
 @ChannelHandler.Sharable
 public class NettyServerHandler extends ChannelInboundHandlerAdapter {

+ 10 - 0
audio-analysis/src/main/java/com/yonge/netty/server/handler/message/BinaryMessageHandler.java

@@ -0,0 +1,10 @@
+package com.yonge.netty.server.handler.message;
+
+import io.netty.channel.Channel;
+
+public interface BinaryMessageHandler {
+	
+	String getAction();
+
+	boolean handler(String user, Channel channel, byte[] bytes);
+}

+ 194 - 0
audio-analysis/src/main/java/com/yonge/netty/server/handler/message/BinaryWebSocketFrameHandler.java

@@ -0,0 +1,194 @@
+package com.yonge.netty.server.handler.message;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import com.yonge.audio.analysis.AudioFloatConverter;
+import com.yonge.audio.utils.ArrayUtil;
+import com.yonge.nettty.dto.UserChannelContext;
+import com.yonge.nettty.dto.WebSocketResponse;
+import com.yonge.nettty.entity.MusicXmlBasicInfo;
+import com.yonge.netty.server.handler.ChannelContextConstants;
+import com.yonge.netty.server.handler.NettyChannelManager;
+import com.yonge.netty.server.processor.WaveformWriter;
+import com.yonge.netty.server.service.UserChannelContextService;
+
+@Component
+@ChannelHandler.Sharable
+public class BinaryWebSocketFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> implements ApplicationContextAware,InitializingBean {
+
+	private final static Logger LOGGER = LoggerFactory.getLogger(BinaryWebSocketFrameHandler.class);
+	
+	@Autowired
+	private NettyChannelManager nettyChannelManager;
+
+	@Autowired
+	private UserChannelContextService userChannelContextService;
+	
+	private ApplicationContext applicationContext;
+	
+	private Map<String, BinaryMessageHandler> handlerMap;
+
+	/**
+	 * @describe 采样率
+	 */
+	private float sampleRate = 44100;
+
+	/**
+	 * 每个采样大小(Bit)
+	 */
+	private int bitsPerSample = 16;
+
+	/**
+	 * 通道数
+	 */
+	private int channels = 1;
+
+	/**
+	 * @describe 采样大小
+	 */
+	private int bufferSize = 1024 * 4;
+
+	private boolean signed = true;
+
+	private boolean bigEndian = false;
+
+	private AudioFormat audioFormat = new AudioFormat(sampleRate, bitsPerSample, channels, signed, bigEndian);
+
+	private AudioFloatConverter converter = AudioFloatConverter.getConverter(audioFormat);
+
+	private String tmpFileDir = "e:/soundRecords/";
+	
+	private SimpleDateFormat sdf =new SimpleDateFormat("yyMMddHHmmSS");
+	
+	@Override
+	protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) throws Exception {
+
+		Channel channel = ctx.channel();
+
+		ByteBuf buf = frame.content().retain();
+
+		try {
+			byte[] datas = ByteBufUtil.getBytes(buf);
+
+			String user = nettyChannelManager.getUser(channel);
+			
+			String action = channel.attr(ChannelContextConstants.CHANNEL_ATTR_KEY_ACTION).get();
+			
+			LOGGER.info("---------ACTION:{}---------",action);
+			
+			if(handlerMap == null){
+				LOGGER.error("消息处理器没有初始化");
+			}
+			BinaryMessageHandler handler = handlerMap.get(action);
+			
+			switch (action) {
+			case "PITCH_DETECTION":
+				handler.handler(user, channel, datas);
+				break;
+			case "SOUND_COMPARE":
+				
+				UserChannelContext channelContext = userChannelContextService.getChannelContext(channel);
+
+				if (channelContext == null) {
+					return;
+				}
+				
+				// 写录音文件
+				WaveformWriter waveFileProcessor = channelContext.getWaveFileProcessor();
+				if (waveFileProcessor == null) {
+					File file = new File(tmpFileDir + user + "_" + sdf.format(new Date()) + ".wav");
+					waveFileProcessor = new WaveformWriter(file.getAbsolutePath());
+					channelContext.setWaveFileProcessor(waveFileProcessor);
+				}
+				waveFileProcessor.process(datas);
+				
+				datas = channelContext.skipHeader(datas);
+
+				if (datas.length == 0) {
+					return;
+				}
+				
+				channelContext.setChannelBufferBytes(ArrayUtil.mergeByte(channelContext.getChannelBufferBytes(), datas));
+				
+				int totalLength = channelContext.getChannelBufferBytes().length;
+				
+				while (totalLength >= bufferSize) {
+					byte[] bufferData = ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), 0, bufferSize - 1);
+
+					if (bufferSize != totalLength) {
+						channelContext.setChannelBufferBytes(ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), bufferSize, totalLength - 1));
+					} else {
+						channelContext.setChannelBufferBytes(new byte[0]);
+					}
+
+					float[] sampleFloats = new float[bufferSize / 2];
+
+					converter.toFloatArray(bufferData, sampleFloats);
+
+					channelContext.handle(sampleFloats, audioFormat);
+
+					MusicXmlBasicInfo musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
+					int sectionIndex = channelContext.getEvaluatingSectionIndex().get();
+
+					// 评分
+					int score = channelContext.evaluateForSection(sectionIndex, musicXmlBasicInfo.getSubjectId());
+					if (score >= 0) {
+
+						Map<String, Object> params = new HashMap<String, Object>();
+						params.put("score", score);
+						params.put("measureIndex", sectionIndex);
+
+						WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("measureScore", params);
+
+						nettyChannelManager.sendTextMessage(user, resp);
+					}
+
+					totalLength = channelContext.getChannelBufferBytes().length;
+				}
+				break;
+
+			default:
+				break;
+			}
+
+		} finally {
+			buf.release();
+		}
+	}
+
+	@Override
+	public void afterPropertiesSet() throws Exception {
+		handlerMap = applicationContext.getBeansOfType(BinaryMessageHandler.class).values().stream()
+				.collect(Collectors.toMap(BinaryMessageHandler::getAction, t -> t));
+	}
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+		this.applicationContext = applicationContext;
+	}
+
+}

+ 5 - 0
audio-analysis/src/main/java/com/yonge/netty/server/handler/message/TextMessageHandler.java

@@ -0,0 +1,5 @@
+package com.yonge.netty.server.handler.message;
+
+public interface TextMessageHandler {
+
+}

+ 228 - 0
audio-analysis/src/main/java/com/yonge/netty/server/handler/message/TextWebSocketHandler.java

@@ -0,0 +1,228 @@
+package com.yonge.netty.server.handler.message;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+
+import java.math.BigDecimal;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPath;
+import com.ym.mec.biz.dal.entity.SysMusicCompareRecord;
+import com.ym.mec.biz.dal.enums.DeviceTypeEnum;
+import com.ym.mec.biz.dal.enums.FeatureType;
+import com.ym.mec.biz.service.SysMusicCompareRecordService;
+import com.ym.mec.thirdparty.storage.StoragePluginContext;
+import com.ym.mec.thirdparty.storage.provider.KS3StoragePlugin;
+import com.ym.mec.util.upload.UploadUtil;
+import com.yonge.nettty.dto.SectionAnalysis;
+import com.yonge.nettty.dto.UserChannelContext;
+import com.yonge.nettty.dto.WebSocketResponse;
+import com.yonge.nettty.entity.MusicXmlBasicInfo;
+import com.yonge.nettty.entity.MusicXmlNote;
+import com.yonge.netty.server.handler.ChannelContextConstants;
+import com.yonge.netty.server.handler.NettyChannelManager;
+import com.yonge.netty.server.processor.WaveformWriter;
+import com.yonge.netty.server.service.UserChannelContextService;
+
+@Component
+@ChannelHandler.Sharable
+public class TextWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(TextWebSocketHandler.class);
+
+	@Autowired
+	private SysMusicCompareRecordService sysMusicCompareRecordService;
+
+    @Autowired
+    private StoragePluginContext storagePluginContext;
+
+	@Autowired
+	private UserChannelContextService userChannelContextService;
+
+	@Autowired
+	private NettyChannelManager nettyChannelManager;
+
+	@Override
+	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
+
+		Channel channel = ctx.channel();
+
+		String jsonMsg = frame.text();
+		
+		LOGGER.info("接收到客户端的消息内容:{}", jsonMsg);
+		
+		String type = (String) JSONPath.extract(jsonMsg, "$.header.type");
+		
+		if(StringUtils.isNoneBlank(type)){
+			channel.attr(ChannelContextConstants.CHANNEL_ATTR_KEY_ACTION).set(type);
+		}
+		
+		if (StringUtils.equals(type, "PITCH_DETECTION")) {// 校音
+			
+			return;
+		} else if (StringUtils.equals(type, "SOUND_COMPARE")) {// 评测
+			String command = (String) JSONPath.extract(jsonMsg, "$.header.commond");
+
+			JSONObject dataObj = (JSONObject) JSONPath.extract(jsonMsg, "$.body");
+
+			UserChannelContext channelContext = userChannelContextService.getChannelContext(channel);
+			
+			MusicXmlBasicInfo musicXmlBasicInfo = null;
+
+			switch (command) {
+			case "musicXml": // 同步music xml信息
+
+				musicXmlBasicInfo = JSONObject.toJavaObject(dataObj, MusicXmlBasicInfo.class);
+
+				userChannelContextService.remove(channel);
+
+				if (channelContext == null) {
+					channelContext = new UserChannelContext();
+				}
+
+				channelContext.getSongMusicXmlMap().put(musicXmlBasicInfo.getExamSongId(), musicXmlBasicInfo);
+				channelContext.init(musicXmlBasicInfo.getHeardLevel(), musicXmlBasicInfo.getSubjectId(), musicXmlBasicInfo.getBeatLength());
+
+				userChannelContextService.register(channel, channelContext);
+
+				break;
+			case "recordStart": // 开始评测
+
+				// 清空缓存信息
+				channelContext.resetUserInfo();
+				
+				musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
+
+				if (musicXmlBasicInfo != null) {
+					Date date = new Date();
+					SysMusicCompareRecord sysMusicCompareRecord = new SysMusicCompareRecord(FeatureType.CLOUD_STUDY_EVALUATION);
+					sysMusicCompareRecord.setCreateTime(date);
+					sysMusicCompareRecord.setUserId(Integer.parseInt(nettyChannelManager.getUser(channel)));
+					sysMusicCompareRecord.setSysMusicScoreId(musicXmlBasicInfo.getExamSongId());
+					sysMusicCompareRecord.setBehaviorId(musicXmlBasicInfo.getBehaviorId());
+					//sysMusicCompareRecord.setClientId();
+					sysMusicCompareRecord.setDeviceType(DeviceTypeEnum.valueOf(musicXmlBasicInfo.getPlatform()));
+					sysMusicCompareRecord.setSpeed(musicXmlBasicInfo.getSpeed());
+					
+					MusicXmlNote musicXmlNote = musicXmlBasicInfo.getMusicXmlInfos().stream().max(Comparator.comparing(MusicXmlNote::getTimeStamp)).get();
+					sysMusicCompareRecord.setSourceTime((float) ((musicXmlNote.getTimeStamp()+musicXmlNote.getDuration())/1000));
+					sysMusicCompareRecordService.insert(sysMusicCompareRecord);
+					channelContext.setRecordId(sysMusicCompareRecord.getId());
+				}
+				break;
+			case "recordEnd": // 结束评测
+			case "recordCancel": // 取消评测
+				if (channelContext == null) {
+					return;
+				}
+
+				WaveformWriter waveFileProcessor = channelContext.getWaveFileProcessor();
+				if (waveFileProcessor != null) {
+					// 写文件头
+					waveFileProcessor.processingFinished();
+				}
+
+				if (StringUtils.equals(command, "recordEnd")) {
+					// 生成评测报告
+					Map<String, Object> params = new HashMap<String, Object>();
+
+					Map<String, Integer> scoreMap = channelContext.evaluateForMusic();
+					for (Entry<String, Integer> entry : scoreMap.entrySet()) {
+						params.put(entry.getKey(), entry.getValue());
+					}
+					
+					//保存评测结果
+					Long recordId = channelContext.getRecordId();
+					SysMusicCompareRecord sysMusicCompareRecord = sysMusicCompareRecordService.get(recordId);
+					if(sysMusicCompareRecord != null){
+						musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
+						
+						if (scoreMap != null && scoreMap.size() > 1) {
+							sysMusicCompareRecord.setScore(new BigDecimal(scoreMap.get("score")));
+							sysMusicCompareRecord.setIntonation(new BigDecimal(scoreMap.get("intonation")));
+							sysMusicCompareRecord.setIntegrity(new BigDecimal(scoreMap.get("integrity")));
+							sysMusicCompareRecord.setCadence(new BigDecimal(scoreMap.get("cadence")));
+							sysMusicCompareRecord.setPlayTime(scoreMap.get("playTime") / 1000);
+						}
+						sysMusicCompareRecord.setFeature(FeatureType.CLOUD_STUDY_EVALUATION);
+
+			            String url = null;
+			            try {
+			                String folder = UploadUtil.getFileFloder();
+			                url = storagePluginContext.asyncUploadFile(KS3StoragePlugin.PLUGIN_NAME,"soundCompare/" + folder, waveFileProcessor.getFile());
+			            } catch (Exception e) {
+			                LOGGER.error("录音文件上传失败:{}", e);
+			            }
+						sysMusicCompareRecord.setRecordFilePath(url);
+						//sysMusicCompareRecord.setVideoFilePath(videoFilePath);
+
+						Map<String, Object> scoreData = new HashMap<>();
+						List<SectionAnalysis> sectionAnalysisList = channelContext.getDoneSectionAnalysisList();
+						sectionAnalysisList = sectionAnalysisList.stream().filter(t -> t.isIngore() == false).collect(Collectors.toList());
+						scoreData.put("userMeasureScore", sectionAnalysisList.stream().collect(Collectors.toMap(SectionAnalysis :: getIndex, t -> t)));
+
+						Map<String, Object> musicalNotesPlayStats = new HashMap<>();
+						musicalNotesPlayStats.put("detailId", musicXmlBasicInfo.getDetailId());
+						musicalNotesPlayStats.put("examSongId", musicXmlBasicInfo.getExamSongId());
+						musicalNotesPlayStats.put("xmlUrl", musicXmlBasicInfo.getXmlUrl());
+						
+						musicalNotesPlayStats.put("notesData", channelContext.getDoneNoteAnalysisList().stream().filter(t -> t.isIgnore() == false).collect(Collectors.toList()));
+						scoreData.put("musicalNotesPlayStats", musicalNotesPlayStats);
+						sysMusicCompareRecord.setScoreData(JSON.toJSONString(scoreData));
+						
+						sysMusicCompareRecordService.saveMusicCompareData(sysMusicCompareRecord);
+					}
+					
+					WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("overall", params);
+
+					nettyChannelManager.sendTextMessage(nettyChannelManager.getUser(channel), resp);
+				}
+
+				// 清空缓存信息
+				channelContext.resetUserInfo();
+
+				break;
+			case "proxyMessage": // ???
+
+				break;
+			case "videoUpload": // 上传音频
+				SysMusicCompareRecord musicCompareRecord = null;
+				if (dataObj.containsKey("recordId")) {
+					musicCompareRecord = sysMusicCompareRecordService.get(dataObj.getLong("recordId"));
+				}
+				if (Objects.nonNull(musicCompareRecord) && dataObj.containsKey("filePath")) {
+					musicCompareRecord.setVideoFilePath(dataObj.getString("filePath"));
+					sysMusicCompareRecordService.update(musicCompareRecord);
+				} else {
+					musicCompareRecord.setVideoFilePath(musicCompareRecord.getRecordFilePath());
+					sysMusicCompareRecordService.update(musicCompareRecord);
+				}
+				
+				break;
+
+			default:
+				// 非法请求
+				break;
+			}
+		}
+	}
+
+}

+ 0 - 153
audio-analysis/src/main/java/com/yonge/netty/server/messagehandler/BinaryWebSocketFrameHandler.java

@@ -1,153 +0,0 @@
-package com.yonge.netty.server.messagehandler;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.sound.sampled.AudioFormat;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.yonge.audio.analysis.AudioFloatConverter;
-import com.yonge.audio.utils.ArrayUtil;
-import com.yonge.nettty.dto.UserChannelContext;
-import com.yonge.nettty.dto.WebSocketResponse;
-import com.yonge.nettty.entity.MusicXmlBasicInfo;
-import com.yonge.netty.server.NettyChannelManager;
-import com.yonge.netty.server.processor.WaveformWriter;
-import com.yonge.netty.server.service.UserChannelContextService;
-
-@Component
-@ChannelHandler.Sharable
-public class BinaryWebSocketFrameHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {
-
-	@Autowired
-	private NettyChannelManager nettyChannelManager;
-
-	@Autowired
-	private UserChannelContextService userChannelContextService;
-
-	/**
-	 * @describe 采样率
-	 */
-	private float sampleRate = 44100;
-
-	/**
-	 * 每个采样大小(Bit)
-	 */
-	private int bitsPerSample = 16;
-
-	/**
-	 * 通道数
-	 */
-	private int channels = 1;
-
-	/**
-	 * @describe 采样大小
-	 */
-	private int bufferSize = 1024 * 4;
-
-	private boolean signed = true;
-
-	private boolean bigEndian = false;
-
-	private AudioFormat audioFormat = new AudioFormat(sampleRate, bitsPerSample, channels, signed, bigEndian);
-
-	private AudioFloatConverter converter = AudioFloatConverter.getConverter(audioFormat);
-
-	private String tmpFileDir = "e:/soundRecords/";
-	
-	private SimpleDateFormat sdf =new SimpleDateFormat("yyMMddHHmmSS");
-	
-	@Override
-	protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) throws Exception {
-
-		Channel channel = ctx.channel();
-
-		ByteBuf buf = frame.content().retain();
-
-		try {
-			byte[] datas = ByteBufUtil.getBytes(buf);
-
-			String user = nettyChannelManager.getUser(channel);
-
-			UserChannelContext channelContext = userChannelContextService.getChannelContext(channel);
-
-			if (channelContext == null) {
-				return;
-			}
-			
-			datas = channelContext.skipHeader(datas);
-
-			if (datas.length == 0) {
-				return;
-			}
-			
-			// 写录音文件
-			WaveformWriter waveFileProcessor = channelContext.getWaveFileProcessor();
-			if (waveFileProcessor == null) {
-				File file = new File(tmpFileDir + user + "_" + sdf.format(new Date()) + ".wav");
-				waveFileProcessor = new WaveformWriter(file.getAbsolutePath());
-				channelContext.setWaveFileProcessor(waveFileProcessor);
-			}
-			waveFileProcessor.process(datas);
-			
-			channelContext.setChannelBufferBytes(ArrayUtil.mergeByte(channelContext.getChannelBufferBytes(), datas));
-			
-			int totalLength = channelContext.getChannelBufferBytes().length;
-			
-			while(totalLength >= bufferSize){
-				byte[] bufferData = ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), 0, bufferSize - 1);
-				
-				if(bufferSize != totalLength){
-					channelContext.setChannelBufferBytes(ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), bufferSize, totalLength - 1));
-				}else{
-					channelContext.setChannelBufferBytes(new byte[0]);
-				}
-				
-				float[] sampleFloats = new float[bufferSize/2];
-				
-				converter.toFloatArray(bufferData,sampleFloats);
-				
-				channelContext.handle1(sampleFloats, audioFormat);
-
-				/*AudioDispatcher dispatcher = AudioDispatcherFactory.fromFloatArray(sampleFloats, (int)audioFormat.getSampleRate(), bufferSize, overlap);
-				dispatcher.addAudioProcessor(new PitchProcessor(algorithm, sampleRate, bufferSize, channelContext));
-				dispatcher.run();*/
-				
-				MusicXmlBasicInfo musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
-				int sectionIndex = channelContext.getEvaluatingSectionIndex().get();
-				
-				//评分
-				int score = channelContext.evaluateForSection(sectionIndex, musicXmlBasicInfo.getSubjectId());
-				if(score >= 0){
-					
-					Map<String,Object> params = new HashMap<String, Object>();
-					params.put("score", score);
-					params.put("measureIndex", sectionIndex);
-					
-					WebSocketResponse<Map<String,Object>> resp = new WebSocketResponse<Map<String,Object>>("measureScore",params);
-					
-					nettyChannelManager.sendTextMessage(user, resp);
-				}
-				
-				totalLength = channelContext.getChannelBufferBytes().length;
-			}
-
-		} finally {
-			buf.release();
-		}
-	}
-
-}

+ 0 - 220
audio-analysis/src/main/java/com/yonge/netty/server/messagehandler/TextWebSocketHandler.java

@@ -1,220 +0,0 @@
-package com.yonge.netty.server.messagehandler;
-
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-
-import java.math.BigDecimal;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.JSONPath;
-import com.ym.mec.biz.dal.entity.SysMusicCompareRecord;
-import com.ym.mec.biz.dal.enums.DeviceTypeEnum;
-import com.ym.mec.biz.dal.enums.FeatureType;
-import com.ym.mec.biz.service.SysMusicCompareRecordService;
-import com.ym.mec.thirdparty.storage.StoragePluginContext;
-import com.ym.mec.thirdparty.storage.provider.KS3StoragePlugin;
-import com.ym.mec.util.upload.UploadUtil;
-import com.yonge.nettty.dto.SectionAnalysis;
-import com.yonge.nettty.dto.UserChannelContext;
-import com.yonge.nettty.dto.WebSocketResponse;
-import com.yonge.nettty.entity.MusicXmlBasicInfo;
-import com.yonge.nettty.entity.MusicXmlNote;
-import com.yonge.netty.server.NettyChannelManager;
-import com.yonge.netty.server.processor.WaveformWriter;
-import com.yonge.netty.server.service.UserChannelContextService;
-
-@Component
-@ChannelHandler.Sharable
-public class TextWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
-
-	private static final Logger LOGGER = LoggerFactory.getLogger(TextWebSocketHandler.class);
-
-	@Autowired
-	private SysMusicCompareRecordService sysMusicCompareRecordService;
-
-    @Autowired
-    private StoragePluginContext storagePluginContext;
-
-	@Autowired
-	private UserChannelContextService userChannelContextService;
-
-	@Autowired
-	private NettyChannelManager nettyChannelManager;
-
-	@Override
-	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
-
-		Channel channel = ctx.channel();
-
-		String jsonMsg = frame.text();
-		String command = (String) JSONPath.extract(jsonMsg, "$.header.commond");
-
-		JSONObject dataObj = (JSONObject) JSONPath.extract(jsonMsg, "$.body");
-
-		LOGGER.info("接收到客户端的指令[{}]:{}", command, dataObj);
-
-		UserChannelContext channelContext = userChannelContextService.getChannelContext(channel);
-		
-		MusicXmlBasicInfo musicXmlBasicInfo = null;
-
-		switch (command) {
-		case "musicXml": // 同步music xml信息
-
-			musicXmlBasicInfo = JSONObject.toJavaObject(dataObj, MusicXmlBasicInfo.class);
-
-			userChannelContextService.remove(channel);
-
-			if (channelContext == null) {
-				channelContext = new UserChannelContext();
-			}
-
-			channelContext.getSongMusicXmlMap().put(musicXmlBasicInfo.getExamSongId(), musicXmlBasicInfo);
-			channelContext.init(musicXmlBasicInfo.getHeardLevel(), musicXmlBasicInfo.getSubjectId(), musicXmlBasicInfo.getBeatLength());
-
-			userChannelContextService.register(channel, channelContext);
-
-			break;
-		case "recordStart": // 开始评测
-
-			// 清空缓存信息
-			channelContext.resetUserInfo();
-			
-			musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
-
-			if (musicXmlBasicInfo != null) {
-				Date date = new Date();
-				SysMusicCompareRecord sysMusicCompareRecord = new SysMusicCompareRecord(FeatureType.CLOUD_STUDY_EVALUATION);
-				sysMusicCompareRecord.setCreateTime(date);
-				sysMusicCompareRecord.setUserId(Integer.parseInt(nettyChannelManager.getUser(channel)));
-				sysMusicCompareRecord.setSysMusicScoreId(musicXmlBasicInfo.getExamSongId());
-				sysMusicCompareRecord.setBehaviorId(musicXmlBasicInfo.getBehaviorId());
-				//sysMusicCompareRecord.setClientId();
-				sysMusicCompareRecord.setDeviceType(DeviceTypeEnum.valueOf(musicXmlBasicInfo.getPlatform()));
-				sysMusicCompareRecord.setSpeed(musicXmlBasicInfo.getSpeed());
-				
-				MusicXmlNote musicXmlNote = musicXmlBasicInfo.getMusicXmlInfos().stream().max(Comparator.comparing(MusicXmlNote::getTimeStamp)).get();
-				sysMusicCompareRecord.setSourceTime((float) ((musicXmlNote.getTimeStamp()+musicXmlNote.getDuration())/1000));
-				sysMusicCompareRecordService.insert(sysMusicCompareRecord);
-				channelContext.setRecordId(sysMusicCompareRecord.getId());
-			}
-			break;
-		case "recordEnd": // 结束评测
-		case "recordCancel": // 取消评测
-			if (channelContext == null) {
-				return;
-			}
-
-			WaveformWriter waveFileProcessor = channelContext.getWaveFileProcessor();
-			if (waveFileProcessor != null) {
-				// 写文件头
-				waveFileProcessor.processingFinished();
-			}
-
-			if (StringUtils.equals(command, "recordEnd")) {
-				// 生成评测报告
-				Map<String, Object> params = new HashMap<String, Object>();
-
-				Map<String, Integer> scoreMap = channelContext.evaluateForMusic();
-				for (Entry<String, Integer> entry : scoreMap.entrySet()) {
-					params.put(entry.getKey(), entry.getValue());
-				}
-				
-				//保存评测结果
-				Long recordId = channelContext.getRecordId();
-				SysMusicCompareRecord sysMusicCompareRecord = sysMusicCompareRecordService.get(recordId);
-				if(sysMusicCompareRecord != null){
-					musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
-					
-					if (scoreMap != null && scoreMap.size() > 1) {
-						sysMusicCompareRecord.setScore(new BigDecimal(scoreMap.get("score")));
-						sysMusicCompareRecord.setIntonation(new BigDecimal(scoreMap.get("intonation")));
-						sysMusicCompareRecord.setIntegrity(new BigDecimal(scoreMap.get("integrity")));
-						sysMusicCompareRecord.setCadence(new BigDecimal(scoreMap.get("cadence")));
-						sysMusicCompareRecord.setPlayTime(scoreMap.get("playTime") / 1000);
-					}
-					sysMusicCompareRecord.setFeature(FeatureType.CLOUD_STUDY_EVALUATION);
-
-		            String url = null;
-		            try {
-		                String folder = UploadUtil.getFileFloder();
-		                url = storagePluginContext.asyncUploadFile(KS3StoragePlugin.PLUGIN_NAME,"soundCompare/" + folder, waveFileProcessor.getFile());
-		            } catch (Exception e) {
-		                LOGGER.error("录音文件上传失败:{}", e);
-		            }
-					sysMusicCompareRecord.setRecordFilePath(url);
-					//sysMusicCompareRecord.setVideoFilePath(videoFilePath);
-
-					Map<String, Object> scoreData = new HashMap<>();
-					List<SectionAnalysis> sectionAnalysisList = channelContext.getDoneSectionAnalysisList();
-					sectionAnalysisList = sectionAnalysisList.stream().filter(t -> t.isIngore() == false).collect(Collectors.toList());
-					scoreData.put("userMeasureScore", sectionAnalysisList.stream().collect(Collectors.toMap(SectionAnalysis :: getIndex, t -> t)));
-
-					Map<String, Object> musicalNotesPlayStats = new HashMap<>();
-					musicalNotesPlayStats.put("detailId", musicXmlBasicInfo.getDetailId());
-					musicalNotesPlayStats.put("examSongId", musicXmlBasicInfo.getExamSongId());
-					musicalNotesPlayStats.put("xmlUrl", musicXmlBasicInfo.getXmlUrl());
-					
-					musicalNotesPlayStats.put("notesData", channelContext.getDoneNoteAnalysisList().stream().filter(t -> t.isIgnore() == false).collect(Collectors.toList()));
-					scoreData.put("musicalNotesPlayStats", musicalNotesPlayStats);
-					sysMusicCompareRecord.setScoreData(JSON.toJSONString(scoreData));
-					
-					sysMusicCompareRecordService.saveMusicCompareData(sysMusicCompareRecord);
-				}
-				
-				WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("overall", params);
-
-				nettyChannelManager.sendTextMessage(nettyChannelManager.getUser(channel), resp);
-			}
-
-			// 清空缓存信息
-			channelContext.resetUserInfo();
-
-			break;
-		case "proxyMessage": // ???
-
-			break;
-		case "videoUpload": // 上传音频
-			SysMusicCompareRecord musicCompareRecord = null;
-			if (dataObj.containsKey("recordId")) {
-				musicCompareRecord = sysMusicCompareRecordService.get(dataObj.getLong("recordId"));
-			}
-			if (Objects.nonNull(musicCompareRecord) && dataObj.containsKey("filePath")) {
-				musicCompareRecord.setVideoFilePath(dataObj.getString("filePath"));
-				sysMusicCompareRecordService.update(musicCompareRecord);
-			} else {
-				musicCompareRecord.setVideoFilePath(musicCompareRecord.getRecordFilePath());
-				sysMusicCompareRecordService.update(musicCompareRecord);
-			}
-			
-			break;
-		case "checkSound": // 校音
-			
-			
-
-			break;
-
-		default:
-			// 非法请求
-			break;
-		}
-	}
-
-}

+ 135 - 0
audio-analysis/src/main/java/com/yonge/netty/server/service/CompareHandler.java

@@ -0,0 +1,135 @@
+package com.yonge.netty.server.service;
+
+import io.netty.channel.Channel;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.yonge.audio.analysis.AudioFloatConverter;
+import com.yonge.audio.utils.ArrayUtil;
+import com.yonge.nettty.dto.UserChannelContext;
+import com.yonge.nettty.dto.WebSocketResponse;
+import com.yonge.nettty.entity.MusicXmlBasicInfo;
+import com.yonge.netty.server.handler.NettyChannelManager;
+import com.yonge.netty.server.handler.message.BinaryMessageHandler;
+import com.yonge.netty.server.processor.WaveformWriter;
+
+@Component
+public class CompareHandler implements BinaryMessageHandler {
+
+	@Autowired
+	private UserChannelContextService userChannelContextService;
+
+	@Autowired
+	private NettyChannelManager nettyChannelManager;
+
+	/**
+	 * @describe 采样率
+	 */
+	private float sampleRate = 44100;
+
+	/**
+	 * 每个采样大小(Bit)
+	 */
+	private int bitsPerSample = 16;
+
+	/**
+	 * 通道数
+	 */
+	private int channels = 1;
+
+	/**
+	 * @describe 采样大小
+	 */
+	private int bufferSize = 1024 * 4;
+
+	private boolean signed = true;
+
+	private boolean bigEndian = false;
+
+	private AudioFormat audioFormat = new AudioFormat(sampleRate, bitsPerSample, channels, signed, bigEndian);
+
+	private AudioFloatConverter converter = AudioFloatConverter.getConverter(audioFormat);
+
+	private String tmpFileDir = "e:/soundRecords/";
+
+	private SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmSS");
+
+	@Override
+	public String getAction() {
+		return "SOUND_COMPARE";
+	}
+
+	@Override
+	public boolean handler(String user, Channel channel, byte[] datas) {
+		UserChannelContext channelContext = userChannelContextService.getChannelContext(channel);
+
+		if (channelContext == null) {
+			return false;
+		}
+
+		// 写录音文件
+		WaveformWriter waveFileProcessor = channelContext.getWaveFileProcessor();
+		if (waveFileProcessor == null) {
+			File file = new File(tmpFileDir + user + "_" + sdf.format(new Date()) + ".wav");
+			waveFileProcessor = new WaveformWriter(file.getAbsolutePath());
+			channelContext.setWaveFileProcessor(waveFileProcessor);
+		}
+		waveFileProcessor.process(datas);
+
+		datas = channelContext.skipHeader(datas);
+
+		if (datas.length == 0) {
+			return false;
+		}
+
+		channelContext.setChannelBufferBytes(ArrayUtil.mergeByte(channelContext.getChannelBufferBytes(), datas));
+
+		int totalLength = channelContext.getChannelBufferBytes().length;
+
+		while (totalLength >= bufferSize) {
+			byte[] bufferData = ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), 0, bufferSize - 1);
+
+			if (bufferSize != totalLength) {
+				channelContext.setChannelBufferBytes(ArrayUtil.extractByte(channelContext.getChannelBufferBytes(), bufferSize, totalLength - 1));
+			} else {
+				channelContext.setChannelBufferBytes(new byte[0]);
+			}
+
+			float[] sampleFloats = new float[bufferSize / 2];
+
+			converter.toFloatArray(bufferData, sampleFloats);
+
+			channelContext.handle(sampleFloats, audioFormat);
+
+			MusicXmlBasicInfo musicXmlBasicInfo = channelContext.getMusicXmlBasicInfo(null);
+			int sectionIndex = channelContext.getEvaluatingSectionIndex().get();
+
+			// 评分
+			int score = channelContext.evaluateForSection(sectionIndex, musicXmlBasicInfo.getSubjectId());
+			if (score >= 0) {
+
+				Map<String, Object> params = new HashMap<String, Object>();
+				params.put("score", score);
+				params.put("measureIndex", sectionIndex);
+
+				WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("measureScore", params);
+
+				nettyChannelManager.sendTextMessage(user, resp);
+			}
+
+			totalLength = channelContext.getChannelBufferBytes().length;
+		}
+
+		return true;
+	}
+
+}

+ 84 - 0
audio-analysis/src/main/java/com/yonge/netty/server/service/PitchDetectionHandler.java

@@ -0,0 +1,84 @@
+package com.yonge.netty.server.service;
+
+import io.netty.channel.Channel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.yonge.audio.analysis.AudioFloatConverter;
+import com.yonge.audio.analysis.detector.YINPitchDetector;
+import com.yonge.nettty.dto.WebSocketResponse;
+import com.yonge.netty.server.handler.NettyChannelManager;
+import com.yonge.netty.server.handler.message.BinaryMessageHandler;
+
+@Component
+public class PitchDetectionHandler implements BinaryMessageHandler {
+	
+	private final static Logger LOGGER = LoggerFactory.getLogger(PitchDetectionHandler.class);
+
+	/**
+	 * @describe 采样率
+	 */
+	private float sampleRate = 44100;
+
+	/**
+	 * 每个采样大小(Bit)
+	 */
+	private int bitsPerSample = 16;
+
+	/**
+	 * 通道数
+	 */
+	private int channels = 1;
+	
+	private boolean signed = true;
+
+	private boolean bigEndian = false;
+
+	private AudioFormat audioFormat = new AudioFormat(sampleRate, bitsPerSample, channels, signed, bigEndian);
+
+	private AudioFloatConverter converter = AudioFloatConverter.getConverter(audioFormat);
+	
+	@Autowired
+	private NettyChannelManager nettyChannelManager;
+	
+	@Override
+	public String getAction() {
+		return "PITCH_DETECTION";
+	}
+
+	@Override
+	public boolean handler(String userId, Channel channel, byte[] bytes) {
+
+		float[] samples = new float[bytes.length / 2];
+
+		if (samples.length == 0) {
+			return false;
+		}
+
+		converter.toFloatArray(bytes, samples);
+
+		YINPitchDetector frequencyDetector = new YINPitchDetector(samples.length, audioFormat.getSampleRate());
+
+		int playFrequency = (int) frequencyDetector.getFrequency(samples);
+		
+		LOGGER.info("校音频率:{}", playFrequency);
+
+		Map<String, Object> params = new HashMap<String, Object>();
+		params.put("frequency", playFrequency);
+
+		WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("checking", params);
+
+		nettyChannelManager.sendTextMessage(userId, resp);
+
+		return true;
+	}
+	
+}