在BAE tomcat环境下实现讯飞TTS在线文字转语音

原文地址:http://blog.csdn.net/luhanglei/article/details/73246146

市场部同学忽然说,能不能在叮咚音箱的skill里,用方言对用户进行回复。因为叮咚音箱支持回复一段媒体文件,所以应该具有可行性。查了下,支持方言的TTS,只找到了讯飞一家。但是他家的java SDK只有播放和下载两种,而下载还是PCM格式的,因此需要把讯飞家SDK实现为一种通过网址进行请求的模式。

隐藏BUFF:BAE环境下,只有特定的路径是可以进行写操作的,所以临时文件路径有要求。

最终效果:打开http://***.duapp.com/tts?text=你要说的话,即可获取到一段wav音频

1.导入讯飞SDK

把lib里的两个jar文件放到项目的Lib里;

dll和so文件,通过git或者svn传到ROOT.war所在的文件夹里;

并按照百度官方的说明,配置好tomcat的路径

2.servlet代码如下

原理就是,利用讯飞的java API,把生成的PCM 文件放到bae允许进行写操作的临时路径下,并转成WAV格式,进行输出。

请求参数只有一个,text,值就是要转换的文字

/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String text = request.getParameter("text");// 获取需要说的话
		File f = new File("/home/bae/" + text + ".wav");// bae允许的临时文件目录

		// TODO Auto-generated method stub
		SpeechUtility.createUtility(SpeechConstant.APPID + "=******** ");// 讯飞APPID
		// 1.创建SpeechSynthesizer对象
		SpeechSynthesizer mTts = SpeechSynthesizer.createSynthesizer();
		// 2.合成参数设置,详见《MSC Reference Manual》SpeechSynthesizer 类
		mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaokun");// 设置发音人
		mTts.setParameter(SpeechConstant.SPEED, "50");// 设置语速,范围0~100
		mTts.setParameter(SpeechConstant.PITCH, "50");// 设置语调,范围0~100
		mTts.setParameter(SpeechConstant.VOLUME, "100");// 设置音量,范围0~100
		// 3.开始合成
		// 设置合成音频保存位置
		// 合成监听器
		MySynthesizeToUriListener synthesizeToUriListener = new MySynthesizeToUriListener();
		mTts.synthesizeToUri(text, "/home/bae/" + text + ".pcm", synthesizeToUriListener);
		while (!synthesizeToUriListener.isFinish()) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		try {
			convertAudioFiles("/home/bae/" + text + ".pcm", "/home/bae/" + text + ".wav");
		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
			return;
		}

		// 处理请求
		// 读取要下载的文件

		if (f.exists()) {
			FileInputStream fis = new FileInputStream(f);
			byte[] b = new byte[fis.available()];
			fis.read(b);
			response.setCharacterEncoding("utf-8");
			response.setHeader("Content-type", "audio/x-wav");
			// 获取响应报文输出流对象
			ServletOutputStream out = response.getOutputStream();
			// 输出
			out.write(b);
			out.flush();
			out.close();
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

	class MySynthesizeToUriListener implements SynthesizeToUriListener {
		public boolean isFinish = false;

		// progress为合成进度0~100
		public void onBufferProgress(int progress) {
			if (progress == 100)
				isFinish = true;
		}

		// 会话合成完成回调接口
		// uri为合成保存地址,error为错误信息,为null时表示合成会话成功
		@Override
		public void onSynthesizeCompleted(String uri, SpeechError error) {
			isFinish = true;

		}

		@Override
		public void onEvent(int arg0, int arg1, int arg2, int arg3, Object arg4, Object arg5) {
			// TODO 自动生成的方法存根

		}

		public boolean isFinish() {
			return isFinish;
		}

		public void setFinish(boolean isFinish) {
			this.isFinish = isFinish;
		}

	}

	private void convertAudioFiles(String src, String target) throws Exception {
		FileInputStream fis = new FileInputStream(src);
		FileOutputStream fos = new FileOutputStream(target);

		// 计算长度
		byte[] buf = new byte[1024 * 4];
		int size = fis.read(buf);
		int PCMSize = 0;
		while (size != -1) {
			PCMSize += size;
			size = fis.read(buf);
		}
		fis.close();

		// 填入参数,比特率等等。这里用的是16位单声道 8000 hz
		WaveHeader header = new WaveHeader();
		// 长度字段 = 内容的大小(PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
		header.fileLength = PCMSize + (44 - 8);
		header.FmtHdrLeth = 16;
		header.BitsPerSample = 16;
		header.Channels = 1;
		header.FormatTag = 0x0001;
		header.SamplesPerSec = 16000;
		header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
		header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
		header.DataHdrLeth = PCMSize;

		byte[] h = header.getHeader();

		assert h.length == 44; // WAV标准,头部应该是44字节
		// write header
		fos.write(h, 0, h.length);
		// write data stream
		fis = new FileInputStream(src);
		size = fis.read(buf);
		while (size != -1) {
			fos.write(buf, 0, size);
			size = fis.read(buf);
		}
		fis.close();
		fos.close();
	}

PCM转码感谢:http://blog.csdn.net/xiunai78/article/details/6867331

原文地址:http://blog.csdn.net/luhanglei/article/details/73246146

你可能感兴趣的:(在BAE tomcat环境下实现讯飞TTS在线文字转语音)