Browse Source

音频测试

jek 2 months ago
parent
commit
a6bfd60475

+ 1 - 0
Dockerfile

@@ -6,5 +6,6 @@ ENV LANG C.UTF-8
 COPY ./lib /home/lib
 
 COPY ./target/zhili-station-control-tts-1.0-SNAPSHOT.jar /home/App.jar
+COPY ./target/classes/static/wav/ /static/wav/
 
 #CMD ["java","-Xms8192m","-Xmx8192m", "-jar", "/home/App.jar", "--spring.profiles.active=${PRO_ENV}"]

BIN
lib/common.jet


BIN
lib/xiaofeng.jet


BIN
lib/xiaoyan.jet


+ 0 - 1
msc/40a135cc08b268a4901e45dade94d51b/cfg.ldata

@@ -1 +0,0 @@
-{"latest":1684403664}

+ 0 - 4
msc/40a135cc08b268a4901e45dade94d51b/kaisound.dat

@@ -1,4 +0,0 @@
-2023/05/18 17:54:06
-610c927a2180a38869fa5db850f3f610
-Y㯚›¶š±®ÇzŠCM_e
w¿�J®z
-¬,”r—±ÄYƒÁ†3Þ'ù(üý¡S¹:¢%ß`ítüµ¼ðxOx9†ãa`Fš2?"ÇÜy�¹¹Ìì+7Õ,³

BIN
msc/40a135cc08b268a4901e45dade94d51b/usr.ldata


+ 0 - 17
msc/msc.cfg

@@ -1,17 +0,0 @@
-## Copyright (C) 2010-2015 iFLYTEK.
-## Use ';' and '#' character for notation
-## Note: Commands in this cfg file is case sensitive
-
-[logger]
-##如果用户指定的日志文件路径无效,那么MSC在运行中将不会记录日志信息
-file                             = msc.log
-title                            = Mobile Speech Client
-level                            = -1
-output                           = 1
-filter                           = -1
-style                            = -1
-flush                            = 0
-maxsize                          =
-overwrite                        = 1
-maxfile                          =
-cache                            =

+ 0 - 244
src/main/java/com/zhili/stationcontrol/tts/component/XunFeiTextToSpeech.java

@@ -1,244 +0,0 @@
-package com.zhili.stationcontrol.tts.component;
-
-import com.alibaba.fastjson.JSON;
-import com.zhili.stationcontrol.tts.util.WavPlayUtil;
-import com.sun.jna.Library;
-import com.sun.jna.Native;
-import com.sun.jna.Pointer;
-import com.sun.jna.ptr.IntByReference;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author :HuangBin
- * @description:TODO
- * @date :2023/5/17 19:00
- */
-@Component
-@Slf4j
-public class XunFeiTextToSpeech implements DisposableBean, Runnable {
-
-    Thread thread;
-
-    public static String loginParams;
-
-    public static String sessionBeginParams;
-
-    public static String filename;
-
-    public static String linkFile;
-
-    public static String playWay;
-    @Autowired
-    RedisTemplate redisTemplate;
-
-    @Value("${xunfei_tts.play_way}")
-    public void setPlayWay(String p) {
-        playWay = p;
-    }
-
-    @Value("${xunfei_tts.login_params}")
-    public void setLoginParams(String p) {
-        loginParams = p;
-    }
-
-    @Value("${xunfei_tts.session_begin_params}")
-    public void setSessionBeginParams(String p) {
-        sessionBeginParams = p;
-    }
-
-    @Value("${xunfei_tts.filename}")
-    public void setFilename(String p) {
-        filename = p;
-    }
-
-
-    @Value("${xunfei_tts.link_file}")
-    public void setLinkFile(String p) {
-        linkFile = p;
-    }
-
-    @PostConstruct
-    public void init() {
-        log.info("login_params: {}", loginParams);
-        //登录参数,appid与msc库绑定,请勿随意改动
-        int loginCode = MscLibrary.INSTANCE.MSPLogin(null, null, loginParams);
-        log.info("loginCode: {}", loginCode);
-        if (loginCode != 0) {
-            //登录失败
-            MscLibrary.INSTANCE.MSPLogout();
-            log.info("loginfail:登录失败");
-            return;
-        }
-
-        this.thread = new Thread(this);
-        this.thread.start();
-        log.info("start:线程启动");
-    }
-
-    @Override
-    public void run() {
-        while (true) {
-            RandomAccessFile raf = null;
-            String sessionId = null;
-            try {
-                Object voiceObj = redisTemplate.opsForList().leftPop("ttsList", 500l, TimeUnit.MILLISECONDS);
-                if (voiceObj == null) {
-                    continue;
-                }
-                Map<String, Object> voice = JSON.parseObject(voiceObj.toString(), Map.class);
-                String text = voice.get("txt").toString();
-                Integer vol = Integer.valueOf(voice.get("vol").toString());
-                log.info("speak:{},vol:{}", text, vol);
-                IntByReference errCode = new IntByReference();
-                sessionId = MscLibrary.INSTANCE.QTTSSessionBegin(sessionBeginParams, errCode);
-                if (errCode.getValue() != 0) {
-                    log.error("会话失败:" + errCode.getValue());
-                    throw new RuntimeException("会话失败");
-                }
-                //放入文本
-                int textPutCode = MscLibrary.INSTANCE.QTTSTextPut(sessionId, text, text.getBytes().length, null);
-                if (textPutCode != 0) {
-                    log.error("放入文本失败:" + textPutCode);
-                    throw new RuntimeException("放入文本失败");
-                }
-                raf = new RandomAccessFile(this.filename, "rw");
-                raf.write(new byte[44]);
-                int dataSize = 0;
-                IntByReference audioLen = new IntByReference();
-                IntByReference synthStatus = new IntByReference();
-                while (true) {
-                    Pointer pointer = MscLibrary.INSTANCE.QTTSAudioGet(sessionId, audioLen, synthStatus, errCode);
-                    if (pointer != null && audioLen.getValue() > 0) {
-                        //写入合成内容
-                        raf.write(pointer.getByteArray(0, audioLen.getValue()));
-                        //记录数据长度
-                        dataSize += audioLen.getValue();
-                    }
-                    //转换异常或转换结束跳出循环
-//                    log.error("errCode.getValue():{}", errCode.getValue());
-                    if (errCode.getValue() != 0 || synthStatus.getValue() == 2) {
-                        break;
-                    }
-                }
-                if (textPutCode != 0) {
-                    //获取转换数据失败
-                    log.error("获取转换数据失败");
-                    throw new RuntimeException("获取转换数据失败");
-                }
-                //定位到文件起始位置
-                raf.seek(0);
-                //写入真实头格式
-                raf.write(getWavHeader(dataSize, 16000, 32000, 1, 16));
-                if (playWay.equals("java")) {
-                    WavPlayUtil.play(filename);
-                } else if (playWay.equals("sox")) {
-                    WavPlayUtil.play2(filename, vol);
-                }
-            } catch (Exception e) {
-                e.printStackTrace();
-            } finally {
-                if (sessionId != null) {
-                    MscLibrary.INSTANCE.QTTSSessionEnd(sessionId, "Normal");
-                }
-                if (raf != null) {
-                    try {
-                        raf.close();
-                    } catch (IOException e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void destroy() throws Exception {
-        MscLibrary.INSTANCE.MSPLogout();
-    }
-
-
-    public interface MscLibrary extends Library {
-
-        // DLL文件默认路径为项目根目录,若DLL文件存放在项目外,请使用绝对路径
-        MscLibrary INSTANCE = Native.load("lib/" + XunFeiTextToSpeech.linkFile, MscLibrary.class);
-
-        int MSPLogin(String username, String password, String param);
-
-        int MSPLogout();
-
-        String QTTSSessionBegin(String params, IntByReference errorCode);
-
-        int QTTSTextPut(String sessionID, String textString, int textLen, String params);
-
-        Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);
-
-        int QTTSSessionEnd(String sessionID, String hints);
-    }
-
-    static byte[] getWavHeader(int totalAudioLen, int sampleRate, int byteRate, int nChannels, int weikuan) {
-        long totalDataLen = totalAudioLen + 36;
-        byte[] header = new byte[44];
-        header[0] = 'R'; // RIFF/WAVE header
-        header[1] = 'I';
-        header[2] = 'F';
-        header[3] = 'F';
-        header[4] = (byte) (totalDataLen & 0xff);
-        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
-        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
-        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
-        header[8] = 'W';
-        header[9] = 'A';
-        header[10] = 'V';
-        header[11] = 'E';
-        header[12] = 'f'; // 'fmt ' chunk
-        header[13] = 'm';
-        header[14] = 't';
-        header[15] = ' ';
-        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
-        header[17] = 0;
-        header[18] = 0;
-        header[19] = 0;
-        header[20] = 1; // format = 1
-        header[21] = 0;
-        header[22] = (byte) (nChannels & 0xff);
-        header[23] = (byte) ((nChannels >> 8) & 0xff);
-
-        header[24] = (byte) (sampleRate & 0xff);//采样率
-        header[25] = (byte) ((sampleRate >> 8) & 0xff);
-        header[26] = (byte) ((sampleRate >> 16) & 0xff);
-        header[27] = (byte) ((sampleRate >> 24) & 0xff);
-
-        header[28] = (byte) (byteRate & 0xff);//取八位
-        header[29] = (byte) ((byteRate >> 8) & 0xff);
-        header[30] = (byte) ((byteRate >> 16) & 0xff);
-        header[31] = (byte) ((byteRate >> 24) & 0xff);
-
-        int b = weikuan * nChannels / 8;//每次采样的大小
-        header[32] = (byte) (b & 0xff); // block align
-        header[33] = (byte) ((b >> 8) & 0xff);
-
-        header[34] = (byte) (weikuan & 0xff);//位宽
-        header[35] = (byte) ((weikuan >> 8) & 0xff);
-
-        header[36] = 'd';//data
-        header[37] = 'a';
-        header[38] = 't';
-        header[39] = 'a';
-        header[40] = (byte) (totalAudioLen & 0xff);
-        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
-        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
-        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
-        return header;
-    }
-}

+ 25 - 1
src/main/java/com/zhili/stationcontrol/tts/controller/TtsController.java

@@ -11,6 +11,12 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -29,7 +35,7 @@ public class TtsController {
     @Autowired
     MusicService musicService;
 
-    @Value("${play_path:/home/music/music.mp3}")
+    @Value("${play_path:/static/wav/hdzqdd.wav}")
     String playPath;
 
     @GetMapping("/speak/{txt}")
@@ -82,4 +88,22 @@ public class TtsController {
         musicService.stop();
         return "ok";
     }
+
+    @GetMapping("/music")
+    public void music() throws UnsupportedAudioFileException, IOException, LineUnavailableException, InterruptedException {
+        File file = new File("/static/wav/hdzqdd.wav");
+        // 创建一个AudioInputStream
+        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
+        // 使用Clip类来处理音频流
+        Clip clip = AudioSystem.getClip();
+        // 打开声卡并加载音频数据
+        clip.open(audioInputStream);
+        // 开始播放
+        clip.start();
+        Thread.sleep(clip.getMicrosecondLength() / 1000);
+        // 等待音频播放完成
+        clip.drain();
+        // 关闭声卡
+        clip.close();
+    }
 }

+ 1 - 10
src/main/resources/application-prod.yml

@@ -5,13 +5,4 @@ spring:
   redis:
     host: redis
     port: 6379
-    #password: 123456
-
-xunfei_tts:
-  login_params: "appid = 757cceaf, work_dir = ."
-  session_begin_params: "engine_type = local, voice_name = xiaoyan, text_encoding = UTF8, tts_res_path = fo|/home/lib/xiaoyan.jet;fo|/home/lib/common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"
-  filename: "/home/tts.wav"
-  link_file: "libmsc.so"
-  play_way: sox
-
-play_path: /home/music/music.mp3
+    #password: 123456

+ 1 - 11
src/main/resources/application-test.yml

@@ -4,14 +4,4 @@ server:
 spring:
   redis:
     host: 192.168.3.120
-    port: 6379
-
-
-xunfei_tts:
-  login_params: "appid = 757cceaf, work_dir = ."
-  session_begin_params: "engine_type = local, voice_name = xiaoyan, text_encoding = UTF8, tts_res_path = fo|/home/lib/xiaoyan.jet;fo|/home/lib/common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"
-  filename: "/home/tts.wav"
-  link_file: "libmsc.so"
-  play_way: sox
-
-play_path: /home/music/music.mp3
+    port: 6379

+ 2 - 7
src/main/resources/application.yml

@@ -6,10 +6,5 @@ spring:
     host: 127.0.0.1
     port: 6379
 #    password: 123456
-
-xunfei_tts:
-  login_params: "appid = 9f2ce539, work_dir = ."
-  session_begin_params: "engine_type = local, voice_name = xiaoyan, text_encoding = UTF8, tts_res_path = fo|E:\\projects\\kdxf-test\\lib\\xiaoyan.jet;fo|E:\\projects\\kdxf-test\\lib\\common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"
-  filename: "E:\\projects\\kdxf-test\\wav\\tts.wav"
-  link_file: "msc_x64.dll"
-  play_way: java
+  resources:
+    static-locations: classpath:/static/

BIN
src/main/resources/lib/libmsc.so


BIN
src/main/resources/lib/msc_x64.dll


BIN
src/main/resources/static/wav/hdzqdd.wav


BIN
wav/tts.wav