Java文字转语音功能实现

也许,有些时候,你需要这个需求呢,来上代码

我会写出两种不同方式的文字转语音demo,直接copy走用,节省开发时间

git项目下载地址

1.直接使用jdk的 jacob,效果还不错,特点:免费的
2.百度文字转语音,特点:大厂的API肯定好用,功能不少,这个如果是企业开发,推荐使用,需要收费的,可以直接申请账号注册,有appid 等参数,配置好直接用

项目demo,需要的去git下载吧
Java文字转语音功能实现_第1张图片

需要下载jacob-1.18,网上一堆
项目中引入pom文件


		<!-- https://mvnrepository.com/artifact/com.jacob/jacob 文字转语音 -->
		<dependency>
			<groupId>com.hynnet</groupId>
			<artifactId>jacob</artifactId>
			<version>1.18</version>
		</dependency>

1.java合成方法

package com.jourwon.httpclient.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;


public class Test {

	/**
	 * 语音转文字并播放
	 * 
	 * @param txt
	 */
	public static void textToSpeech(String text) {
		ActiveXComponent ax = null;
		try {
			ax = new ActiveXComponent("Sapi.SpVoice");

			// 运行时输出语音内容
			Dispatch spVoice = ax.getObject();
			// 音量 0-100
			ax.setProperty("Volume", new Variant(100));
			// 语音朗读速度 -10 到 +10
			ax.setProperty("Rate", new Variant(-2));
			// 执行朗读
			Dispatch.call(spVoice, "Speak", new Variant(text));

			// 下面是构建文件流把生成语音文件

			ax = new ActiveXComponent("Sapi.SpFileStream");
			Dispatch spFileStream = ax.getObject();

			ax = new ActiveXComponent("Sapi.SpAudioFormat");
			Dispatch spAudioFormat = ax.getObject();

			// 设置音频流格式
			Dispatch.put(spAudioFormat, "Type", new Variant(22));
			// 设置文件输出流格式
			Dispatch.putRef(spFileStream, "Format", spAudioFormat);
			// 调用输出 文件流打开方法,创建一个.wav文件
			Dispatch.call(spFileStream, "Open", new Variant("./text.mp3"), new Variant(3), new Variant(true));
			// 设置声音对象的音频输出流为输出文件对象
			Dispatch.putRef(spVoice, "AudioOutputStream", spFileStream);
			// 设置音量 0到100
			Dispatch.put(spVoice, "Volume", new Variant(100));
			// 设置朗读速度
			Dispatch.put(spVoice, "Rate", new Variant(-2));
			// 开始朗读
			Dispatch.call(spVoice, "Speak", new Variant(text));

			// 关闭输出文件
			Dispatch.call(spFileStream, "Close");
			Dispatch.putRef(spVoice, "AudioOutputStream", null);

			spAudioFormat.safeRelease();
			spFileStream.safeRelease();
			spVoice.safeRelease();
			ax.safeRelease();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		String s = "当月亮和太阳处于地球两侧,并且月亮和太阳的黄经相差180度时,从地球上看,此时的月亮最圆,称之为“满月”";
		textToSpeech(s);
		File file = new File("result.mp3"); // 打开mp3文件即可播放
		String fileName = "Operator.doc".toString(); // 文件的默认保存名
		// 读到流中
		try {
			InputStream inStream = new FileInputStream("c:/Operator.doc");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} // 文件的存放路径
	}

}

2.百度语音合成方法

package com.jourwon.httpclient.util;

import java.io.File;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class TtsMain {

	public static void main(String[] args) throws Exception {
		(new TtsMain()).run();
	}

	// 填写申请百度语音申请的appkey 申请地址:百度AI开放平台
	private final String appKey = "自己申请";

	// 填写申请百度语音申请的APP SECRET
	private final String secretKey = "自己申请";

	// text 的内容为"欢迎使用百度语音合成"的urlencode,utf-8 编码
	private final String text = "百度百科是百度公司推出的一部内容开放、自由的网络百科全书。";
	// 发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
	private final int per = 0;
	// 语速,取值0-9,默认为5中语速
	private final int spd = 5;
	// 音调,取值0-9,默认为5中语调
	private final int pit = 5;
	// 音量,取值0-9,默认为5中音量
	private final int vol = 5;
	// 调用地址
	public final String url = "https://tsn.baidu.com/text2audio";
	// 用户唯一标识,用来区分用户,填写机器 MAC 地址或 IMEI 码,长度为60以内
	private String cuid = "0322java";

	private void run() throws Exception {
		TokenHolder holder = new TokenHolder(appKey, secretKey, TokenHolder.ASR_SCOPE);
		holder.resfresh();
		String token = holder.getToken();

		String url2 = url + "?tex=" + ConnUtil.urlEncode(text);
		url2 += "&per=" + per;
		url2 += "&spd=" + spd;
		url2 += "&pit=" + pit;
		url2 += "&vol=" + vol;
		url2 += "&cuid=" + cuid;
		url2 += "&tok=" + token;
		url2 += "&lan=zh&ctp=1";
		HttpURLConnection conn = (HttpURLConnection) new URL(url2).openConnection();
		conn.setConnectTimeout(5000);
		String contentType = conn.getContentType();
		if (contentType.contains("mp3")) {
			byte[] bytes = ConnUtil.getResponseBytes(conn);
			// 存在项目根目录下,去文件夹点击可以播放
			File file = new File("result.mp3");
			FileOutputStream os = new FileOutputStream(file);
			os.write(bytes);
			os.close();
			System.out.println("mp3 file write to " + file.getAbsolutePath());
		} else {
			System.err.println("ERROR: content-type= " + contentType);
			String res = ConnUtil.getResponseString(conn);
			System.err.println(res);
		}
	}
}

//工具类

package com.jourwon.httpclient.util;

import org.json.JSONObject;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * token的获取类 将apiKey和secretKey换取token,注意有效期保存在expiresAt
 */
public class TokenHolder {

	public static final String ASR_SCOPE = "audio_voice_assistant_get";

	public static final String TTS_SCOPE = "audio_tts_post";

	/**
	 * url , Token的url,http可以改为https
	 */
	private static final String url = "http://openapi.baidu.com/oauth/2.0/token";

	/**
	 * asr的权限 scope 是 "audio_voice_assistant_get" tts 的权限 scope 是
	 * "audio_tts_post"
	 */
	private String scope;

	/**
	 * 网页上申请语音识别应用获取的apiKey
	 */
	private String apiKey;

	/**
	 * 网页上申请语音识别应用获取的secretKey
	 */
	private String secretKey;

	/**
	 * 保存访问接口获取的token
	 */
	private String token;

	/**
	 * 当前的时间戳,毫秒
	 */
	private long expiresAt;

	/**
	 * @param apiKey
	 *            网页上申请语音识别应用获取的apiKey
	 * @param secretKey
	 *            网页上申请语音识别应用获取的secretKey
	 */
	public TokenHolder(String apiKey, String secretKey, String scope) {
		this.apiKey = apiKey;
		this.secretKey = secretKey;
		this.scope = scope;
	}

	/**
	 * 获取token,refresh 方法后调用有效
	 *
	 * @return
	 */
	public String getToken() {
		return token;
	}

	/**
	 * 获取过期时间,refresh 方法后调用有效
	 *
	 * @return
	 */
	public long getExpiresAt() {
		return expiresAt;
	}

	/**
	 * 获取token
	 *
	 * @return
	 * @throws IOException
	 *             http请求错误
	 * @throws DemoException
	 *             http接口返回不是 200, access_token未获取
	 */
	public void resfresh() throws Exception {
		String getTokenURL = url + "?grant_type=client_credentials" + "&client_id=" + ConnUtil.urlEncode(apiKey)
				+ "&client_secret=" + ConnUtil.urlEncode(secretKey);

		// 打印的url出来放到浏览器内可以复现
		System.out.println("token url:" + getTokenURL);

		URL url = new URL(getTokenURL);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		String result = ConnUtil.getResponseString(conn);
		System.out.println("Token result json:" + result);
		parseJson(result);
	}

	/**
	 * @param result
	 *            token接口获得的result
	 * @throws DemoException
	 */
	private void parseJson(String result) throws Exception {
		JSONObject json = new JSONObject(result);
		if (!json.has("access_token")) {
			// 返回没有access_token字段
			throw new DemoException("access_token not obtained, " + result);
		}
		if (!json.has("scope")) {
			// 返回没有scope字段
			throw new DemoException("scopenot obtained, " + result);
		}
		if (!json.getString("scope").contains(scope)) {
			throw new DemoException("scope not exist, " + scope + "," + result);
		}
		token = json.getString("access_token");
		expiresAt = System.currentTimeMillis() + json.getLong("expires_in") * 1000;
	}
}

//异常处理

package com.jourwon.httpclient.util;

public class DemoException extends Exception {
	public DemoException(String message) {
		super(message);
	}
}

//util相关类

package com.jourwon.httpclient.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URLEncoder;

/**
 * 与连接相关的Util类
 */
public class ConnUtil {

	/**
	 * UrlEncode, UTF-8 编码
	 *
	 * @param str
	 *            原始字符串
	 * @return
	 */
	public static String urlEncode(String str) {
		String result = null;
		try {
			result = URLEncoder.encode(str, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 从HttpURLConnection 获取返回的字符串
	 *
	 * @param conn
	 * @return
	 * @throws IOException
	 * @throws DemoException
	 */
	public static String getResponseString(HttpURLConnection conn) throws IOException, DemoException {
		return new String(getResponseBytes(conn));
	}

	/**
	 * 从HttpURLConnection 获取返回的bytes 注意 HttpURLConnection自身问题,
	 * 400类错误,会直接抛出异常。不能获取conn.getInputStream();
	 *
	 * @param conn
	 * @return
	 * @throws IOException
	 *             http请求错误
	 * @throws DemoException
	 *             http 的状态码不是 200
	 */
	public static byte[] getResponseBytes(HttpURLConnection conn) throws IOException, DemoException {
		int responseCode = conn.getResponseCode();
		if (responseCode != 200) {
			System.err.println("http 请求返回的状态码错误,期望200, 当前是 " + responseCode);
			if (responseCode == 401) {
				System.err.println("可能是appkey appSecret 填错");
			}
			throw new DemoException("http response code is" + responseCode);
		}

		InputStream inputStream = conn.getInputStream();
		byte[] result = getInputStreamContent(inputStream);
		return result;
	}

	/**
	 * 将InputStream内的内容全部读取,作为bytes返回
	 *
	 * @param is
	 * @return
	 * @throws IOException
	 * @see InputStream.read()
	 */
	public static byte[] getInputStreamContent(InputStream is) throws IOException {
		byte[] b = new byte[1024];
		// 定义一个输出流存储接收到的数据
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		// 开始接收数据
		int len = 0;
		while (true) {
			len = is.read(b);
			if (len == -1) {
				// 数据读完
				break;
			}
			byteArrayOutputStream.write(b, 0, len);
		}
		return byteArrayOutputStream.toByteArray();
	}
}

//http工具类

package com.jourwon.httpclient.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.jourwon.httpclient.pojo.HttpClientResult;

/**
 * Description: httpClient工具类
 * 
 * @author JourWon
 * @date Created on 2018年4月19日
 */
public class HttpClientUtils {

	// 编码格式。发送编码格式统一用UTF-8
	private static final String ENCODING = "UTF-8";
	
	// 设置连接超时时间,单位毫秒。
	private static final int CONNECT_TIMEOUT = 6000;
	
	// 请求获取数据的超时时间(即响应时间),单位毫秒。
	private static final int SOCKET_TIMEOUT = 6000;

	/**
	 * 发送get请求;不带请求头和请求参数
	 * 
	 * @param url 请求地址
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doGet(String url) throws Exception {
		return doGet(url, null, null);
	}
	
	/**
	 * 发送get请求;带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 请求参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doGet(String url, Map<String, String> params) throws Exception {
		return doGet(url, null, params);
	}

	/**
	 * 发送get请求;带请求头和请求参数
	 * 
	 * @param url 请求地址
	 * @param headers 请求头集合
	 * @param params 请求参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doGet(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
		// 创建httpClient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();

		// 创建访问的地址
		URIBuilder uriBuilder = new URIBuilder(url);
		if (params != null) {
			Set<Entry<String, String>> entrySet = params.entrySet();
			for (Entry<String, String> entry : entrySet) {
				uriBuilder.setParameter(entry.getKey(), entry.getValue());
			}
		}

		// 创建http对象
		HttpGet httpGet = new HttpGet(uriBuilder.build());
		/**
		 * setConnectTimeout:设置连接超时时间,单位毫秒。
		 * setConnectionRequestTimeout:设置从connect Manager(连接池)获取Connection
		 * 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。
		 * setSocketTimeout:请求获取数据的超时时间(即响应时间),单位毫秒。 如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。
		 */
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
		httpGet.setConfig(requestConfig);
		
		// 设置请求头
		packageHeader(headers, httpGet);

		// 创建httpResponse对象
		CloseableHttpResponse httpResponse = null;

		try {
			// 执行请求并获得响应结果
			return getHttpClientResult(httpResponse, httpClient, httpGet);
		} finally {
			// 释放资源
			release(httpResponse, httpClient);
		}
	}

	/**
	 * 发送post请求;不带请求头和请求参数
	 * 
	 * @param url 请求地址
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doPost(String url) throws Exception {
		return doPost(url, null, null);
	}
	
	/**
	 * 发送post请求;带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doPost(String url, Map<String, String> params) throws Exception {
		return doPost(url, null, params);
	}

	/**
	 * 发送post请求;带请求头和请求参数
	 * 
	 * @param url 请求地址
	 * @param headers 请求头集合
	 * @param params 请求参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doPost(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
		// 创建httpClient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();

		// 创建http对象
		HttpPost httpPost = new HttpPost(url);
		/**
		 * setConnectTimeout:设置连接超时时间,单位毫秒。
		 * setConnectionRequestTimeout:设置从connect Manager(连接池)获取Connection
		 * 超时时间,单位毫秒。这个属性是新加的属性,因为目前版本是可以共享连接池的。
		 * setSocketTimeout:请求获取数据的超时时间(即响应时间),单位毫秒。 如果访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。
		 */
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
		httpPost.setConfig(requestConfig);
		// 设置请求头
		/*httpPost.setHeader("Cookie", "");
		httpPost.setHeader("Connection", "keep-alive");
		httpPost.setHeader("Accept", "application/json");
		httpPost.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
		httpPost.setHeader("Accept-Encoding", "gzip, deflate, br");
		httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36");*/
		packageHeader(headers, httpPost);
		
		// 封装请求参数
		packageParam(params, httpPost);

		// 创建httpResponse对象
		CloseableHttpResponse httpResponse = null;

		try {
			// 执行请求并获得响应结果
			return getHttpClientResult(httpResponse, httpClient, httpPost);
		} finally {
			// 释放资源
			release(httpResponse, httpClient);
		}
	}

	/**
	 * 发送put请求;不带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doPut(String url) throws Exception {
		return doPut(url);
	}

	/**
	 * 发送put请求;带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doPut(String url, Map<String, String> params) throws Exception {
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpPut httpPut = new HttpPut(url);
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
		httpPut.setConfig(requestConfig);
		
		packageParam(params, httpPut);

		CloseableHttpResponse httpResponse = null;

		try {
			return getHttpClientResult(httpResponse, httpClient, httpPut);
		} finally {
			release(httpResponse, httpClient);
		}
	}

	/**
	 * 发送delete请求;不带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doDelete(String url) throws Exception {
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpDelete httpDelete = new HttpDelete(url);
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
		httpDelete.setConfig(requestConfig);

		CloseableHttpResponse httpResponse = null;
		try {
			return getHttpClientResult(httpResponse, httpClient, httpDelete);
		} finally {
			release(httpResponse, httpClient);
		}
	}

	/**
	 * 发送delete请求;带请求参数
	 * 
	 * @param url 请求地址
	 * @param params 参数集合
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult doDelete(String url, Map<String, String> params) throws Exception {
		if (params == null) {
			params = new HashMap<String, String>();
		}

		params.put("_method", "delete");
		return doPost(url, params);
	}
	
	/**
	 * Description: 封装请求头
	 * @param params
	 * @param httpMethod
	 */
	public static void packageHeader(Map<String, String> params, HttpRequestBase httpMethod) {
		// 封装请求头
		if (params != null) {
			Set<Entry<String, String>> entrySet = params.entrySet();
			for (Entry<String, String> entry : entrySet) {
				// 设置到请求头到HttpRequestBase对象中
				httpMethod.setHeader(entry.getKey(), entry.getValue());
			}
		}
	}

	/**
	 * Description: 封装请求参数
	 * 
	 * @param params
	 * @param httpMethod
	 * @throws UnsupportedEncodingException
	 */
	public static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod)
			throws UnsupportedEncodingException {
		// 封装请求参数
		if (params != null) {
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			Set<Entry<String, String>> entrySet = params.entrySet();
			for (Entry<String, String> entry : entrySet) {
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}

			// 设置到请求的http对象中
			httpMethod.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
		}
	}

	/**
	 * Description: 获得响应结果
	 * 
	 * @param httpResponse
	 * @param httpClient
	 * @param httpMethod
	 * @return
	 * @throws Exception
	 */
	public static HttpClientResult getHttpClientResult(CloseableHttpResponse httpResponse,
			CloseableHttpClient httpClient, HttpRequestBase httpMethod) throws Exception {
		// 执行请求
		httpResponse = httpClient.execute(httpMethod);

		// 获取返回结果
		if (httpResponse != null && httpResponse.getStatusLine() != null) {
			String content = "";
			if (httpResponse.getEntity() != null) {
				content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
			}
			return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content);
		}
		return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR);
	}

	/**
	 * Description: 释放资源
	 * 
	 * @param httpResponse
	 * @param httpClient
	 * @throws IOException
	 */
	public static void release(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient) throws IOException {
		// 释放资源
		if (httpResponse != null) {
			httpResponse.close();
		}
		if (httpClient != null) {
			httpClient.close();
		}
	}

}

你可能感兴趣的:(Java)