我的编程空间,编程开发者的网络收藏夹
学习永远不晚

让Java说话! (转)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

让Java说话! (转)

让Java说话! (转)[@more@]

  让Java说话!
 为你的Java 1.3 应用程序和Applet添加说话能力
概要
这篇文章中,Tony Loton展示了不使用硬件和本地调用的,少于150行Java代码实现一个简单的语音引擎。此外,他提供了一个小zip文件,里面包含了使Java应用程序说话说需要的东西—仅仅用来娱乐或别的真正的应用程序。如果你刚刚接触Java Sound api,这篇文章将是一个很好的介绍。(1800字)

作者:Tony Loton
译者:Cocia Lin

  为什么要使你的程序说话呢?首先,为了娱乐,这很适合象游戏这样的娱乐程序。并且还有很多严肃的应用领域。我想这虽然不是可视化界面的天生缺点,也是声音可用之处-- 或者过分一点 – 可以使你的眼睛离开你正在做的事情。

  最近,我曾经应用一些技术在web上获得HTML和XML信息的工作[请看 "Access the World's Biggest Database with Web DataBase Connectivity" (JavaWorld, March 2001)]。这让我将那个工作和我的这个想法结合来创建一个说话的Web浏览器。这样的一个浏览器可以使你听到你喜欢的网站上的信息摘录 – 新闻标题,例如 – 就象在外边溜狗或开车上班的途中收听收音机一样。当然,以现在的科技水平,你必须带上你的笔记本电脑和移动电话,但这些不切实际的设想在不久的将来,随着应用Java技术的智能电话的出现而变成现实,例如Nokia 9210(在美国叫9290).

  也许对现在来说,能用的到的是一个eMail朗读器,这也得谢谢JavaMail API.这样的程序将定期的检查你的电子邮箱,并且你的注意被一个声音“你有新的email,你要我给你朗读吗?”吸引。相近的,考虑语音提醒 – 当连接到你的日常管理程序时 –- 电脑大喊“不要忘了10分钟后你和老板的会议!”

  回到这些想法,或者你有更好的自己的想法,我们继续。我将演示怎样将我提供的zip文件添加的我们的工作中,这样,如果你觉得这些东西太难了,你就可以直接安装运行而跳过实现细节。

测试语音引擎
  为了使用这个语音引擎,你需要将jw-0817-javatalk.zip添加到你的classpath,在命令行方式或Java程序中使用com.lotontech.speech.Talker。

命令行方式,象下面这样运行,输入:


java com.lotontech.speech.Talker "h|e|l|oo"

在Java程序中,简单的包含着两行代码:


com.lotontech.speech.Talker talker=new com.lotontech.speech.Talker();
talker.sayPhoneword("h|e|l|oo");

这里,你可能想知道命令行方式或sayPhoneWord(..)方法中的字符串格式”h|e|l|oo”的含义。让我来解释。

  语音引擎依靠联结人的最小的语音单位的短声音例子来工作 – 在这里是英语。这些声音例子,叫做音体变位(allophone),是一个,两个,或三个字母标识符的标志。有些标识符是明显的,有些是不明显的,你能从语音学里看到这样的”hello”的表示。

h --发音你能想到
e --发音你能想到
l --发音你能想到,但注意,我将两个 “l” 变为一个”l”
oo -- “hello”的发音,不是”bot”的,也不是”too”的
这里列出了能用到的音体变(allophone):

a -- 例如 cat
b -- 例如 cab
c -- 例如 cat
d -- 例如 dot
e -- 例如 bet
f -- 例如 frog
g -- 例如 frog
h -- 例如 hog
i -- 例如 pig
j -- 例如 jig
k -- 例如 keg
l -- 例如 leg
m -- 例如 met
n -- 例如 begin
o -- 例如 not
p -- 例如 pot
r -- 例如 rot
s -- 例如 sat
t -- 例如 sat
u -- 例如 put
v -- 例如 have
w -- 例如 wet
y -- 例如 yet
z -- 例如 zoo
aa -- 例如 fake
ay -- 例如 hay
ee -- 例如 bee
ii -- 例如 high
oo -- 例如 go
bb -- 变调b
dd --变调d
ggg -- 变调g
hh --变调h
ll --变调l
nn --变调n
rr -- 变调r
tt -- 变调t
yy --变调y
ar -- 例如 car
aer -- 例如 care
ch -- 例如 which
ck -- 例如 check
ear -- 例如 beer
er -- 例如 later
err -- 例如 later (longer sound)
ng -- 例如 feeding
or -- 例如 law
ou -- 例如 zoo
ouu -- 例如 zoo (longer sound)
ow -- 例如 cow
oy -- 例如 boy
sh -- 例如 shut
th -- 例如 thing
dth -- 例如 this
uh -- 变调 u
wh -- 例如 where
zh -- 例如 Asian
人说话的每一个句子都有单词的升调和降调的变化。这个音调使说话听起来自然,富有感情,并且可以从句子语调确定这是疑问句。如果你听过Stephen Hawking的人造声音,你就能够理解我所说的了。考虑这两个句子:

It is fake -- f|aa|k
Is it fake? -- f|AA|k
你也许猜想,使用升调的方法是用大写字母。你要实际感受一下,我的提示是你要注意听元音字母

  这是你使用这个软件需要知道的全部了,但是如果你对引擎罩下面的东西感兴趣,那么继续往下读。

实现语音引擎

  语音引擎仅仅需要一个类来实现,包含四个方法。它使用j2se1.3的Java Sound API。我不想提供一个全面的Java Sound API教程,你将通过例子学习。你将发现不是有很多需要你来做,并且说明能告诉你需要知道的。

这里是Talker类的基本定义:


package com.lotontech.speech;

import javax.sound.sampled.*;
import java.io.*;
import java.util.*;
import java.NET.*;

public class Talker
{
  private sourceDataLine line=null;
}

如果你从命令行运行程序,下面的main(..)方法将作为一个入口服务。它取得命令行的第一个参数,如果有一个参数,将传递给sayPhoneWord(…)方法:



public static void main(String args[])
{
  Talker player=new Talker();
  if (args.length>0) player.sayPhoneWord(args[0]);
  System.exit(0);
}

上面,SayPhoneWord(…)方法被main(…)方法调用,或者它被Java程序或Applet直接调用。它看起来比它本身难理解。本质上,它简单的一步一步解释单词的语音变位allophone – 被”|”标志分割的输入文本 – 在把他们一个一个通过声音输出通道输出。为了让它听起来更自然,合并每一个声音的结尾到下一个声音的开头:


public void sayPhoneWord(String word)
{
// 为上一个声音设置一个字节数组
  byte[] previousSound=null;

//分割输入字符串
  StringTokenizer st=new StringTokenizer(word,"|",false);
  while (st.hasMoreTokens())
  {
 

为语音单位构造一个文件名
  String thisPhoneFile=st.nextToken();
  thisPhoneFile="/allophones/"+thisPhoneFile+".au";


  从文件中获得数据
  byte[] thisSound=getSound(thisPhoneFile);

  if (previousSound!=null)
  {
 

  合并上一个语音和现在的这个
  int mergeCount=0;
  if (previousSound.length>=500 && thisSound.length>=500)
  mergeCount=500;
  for (int i=0; i  {
  previousSound[previousSound.length-mergeCount+i]
  =(byte)((previousSound[previousSound.length
  -mergeCount+i]+thisSound[i])/2);
  }


  播放前一个音符
  playSound(previousSound);


  切割当前的音符作为前一个音符
  byte[] newSound=new byte[thisSound.length-mergeCount];
  for (int ii=0; ii  newSound[ii]=thisSound[ii+mergeCount];
  previousSound=newSound;
  }
  else
  previousSound=thisSound;
  }


  //播放最终声音和刷新声音通道
  playSound(previousSound);
  drain();
}

在sayPhoneWord()结尾,你看到它调用playSound(..)来输出单独的声音例子,并且调用drain(..)来刷新声音通道。这里是playSound(..)的代码:



private void playSound(byte[] data)
{
  if (data.length>0) line.write(data, 0, data.length);
}

drain(..)的代码:



private void drain()
{
  if (line!=null) line.drain();
  try {Thread.sleep(100);} catch (Exception e) {}
}

现在,如果你回头看看sayPhoneWord(..)方法,你将发现还有一个方法我们还没有提到:getSound(..).


getSound(..)从事先录制好的au文件中读出声音的字节数据。当我说文件时,指的是我提供的zip文件里的资源。我强调这点差别,因为你得到JAR资源控制 – 使用getResource(..)方法 – 这不同于得到一个普通文件的控制权。

为了有一个语音一个语音的读出数据,转换到声音格式,实例化一个声音输出行(为什么他们叫它SourceDateLine,我不知道),组合这些字节数据,我在下面代码中提供给你说明:



private byte[] getSound(String fileName)
{
  try
  {
  URL url=Talker.class.getResource(fileName);
  AudioInputStream stream = AudioSystem.getAudioInputStream(url);

  AudioFormat format = stream.getFormat();

 

转换一个ALAW/ULAW声音到PCM
  if ((format.getEncoding() == AudioFormat.Encoding.ULAW) ||
  (format.getEncoding() == AudioFormat.Encoding.ALAW))
  {
  AudioFormat tmpFormat = new AudioFormat(
  AudioFormat.Encoding.PCM_SIGNED,
  format.getSampleRate(),
  format.getSampleSizeInBits() * 2,
  format.getChannels(),
  format.getFrameSize() * 2,
  format.getFrameRate(),
  true);

  stream = AudioSystem.getAudioInputStream(tmpFormat, stream);
  format = tmpFormat;
  }

  DataLine.Info info = new DataLine.Info(
  Clip.class,
  format,
  ((int) stream.getFrameLength() * format.getFrameSize()));

  if (line==null)
  {
  // -- Output line not instantiated yet –
  // -- Can we find a suitable kind of line? --
  DataLine.Info outInfo = new DataLine.Info(SourceDataLine.class,
  format);
  if (!AudioSystem.isLineSupported(outInfo))
  {
  System.out.println("Line matching " + outInfo + " not supported.");
  throw new Exception("Line matching " + outInfo + " not supported.");
  }

 

打开资源数据行(输出行output line)
  line = (SourceDataLine) AudioSystem.getLine(outInfo);
  line.open(format, 50000);
  line.start();
  }

//一些尺寸计算
  int frameSizeInBytes = format.getFrameSize();
  int bufferLengthInFrames = line.getBufferSize() / 8;
  int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;

  byte[] data=new byte[bufferLengthInBytes];

  //读出数据字节并计算
  int numBytesRead = 0;
  if ((numBytesRead = stream.read(data)) != -1)
  {
  int numBytesRemaining = numBytesRead;
  }

 

//裁剪字节数组到正确尺寸
  byte[] newData=new byte[numBytesRead];
  for (int i=0; i  newData[i]=data[i];

  return newData;
  }
  catch (Exception e)
  {
  return new byte[0];
  }
}

好了,就这么多。一个150行的语音合成器代码,包括说明。但这没有完全结束。

文本到语音(Text-to-speech)的转换
用语音学方法表示单词可能太乏味,所以,如果你想创建一个象我介绍一样的应用程序,你要提供原始文本。

研究过这个题目后,我在zip文件中提供一个实验性的文本到语音的转换类。当你运行它后,将输出给你你想要的语音表示。

在命令行模式,运行text-to-speech转换器:


java com.lotontech.speech.Converter "hello there"

你看到的输出类似下面这样:


hello -> h|e|l|oo
there -> dth|aer

或者,象这样运行它:


java com.lotontech.speech.Converter "I like to read JavaWorld"

看到(并且听到)这些:


i -> ii
like -> l|ii|k
to -> t|ouu
read -> r|ee|a|d
java -> j|a|v|a
world -> w|err|l|d

如果你想知道它是怎样工作的,我将告诉你我的方法很简单,应用通常的顺序的一套文本替换规则。有几个例子规则,你可能喜欢应用精神上的,顺序的方式,这些例子是”ant”,”want”,”wanted”,”unwanted”,”unique”:

替换 "*unique*"使用 "|y|ou|n|ee|k|"
替换"*want*"使用"|w|o|n|t|"
替换"*a*"使用"|a|"
替换"*e*"使用"|e|"
替换"*d*"使用"|d|"
替换"*n*" 使用"|n|"
替换"*u*"使用"|u|"
替换"*t*" 使用"|t|"
”unwanted”的顺序将是这样:


unwanted
un[|w|o|n|t|]ed (rule 2)
[|u|][|n|][|w|o|n|t|][|e|][|d|] (rules 4, 5, 6, 7)
u|n|w|o|n|t|e|d (with surplus characters removed)

你应该看到,包含ant的want被用几种不同的方式朗读。你也应该看到对于unique来说的特殊情况,应该被读为y|ou..而不是u|n….

电脑里的精灵,对你说话
这篇文章提供一个可以使用Java 1.3运行的简便的语音引擎。如果你研究这些代码,你可以得到一些关于JavaSound API播放音频片断的有用方法。要想使这个引擎真的能用,你要思考文本到语音的转换方法,这真的是我的一个主要想法。在这个引擎中,你要想出大量的文本转换规则,还要应用一些好的优先顺序。我希望你有比我强的毅力。

最后,你可能还记得我说过的Nokia 9210。我有一部,它支持Java,我决定用Java使它说话。我也想使applet(Java2的以前版本)在浏览器中说话。这些技术依靠J2SE 1.3声音引擎,现在是可用的。一个不同的方法是需要的,依靠简单的Java AudioClip 接口。不像你想象的那样简单,但我在其上工作。

关于作者
Tony Loton
为他的公司工作 – LOTONTech Limited – 提供软件解决方案,顾问,培训和技术写作服务。写作的小虫好像在这一年里始终叮咬着他,他为John Wiley & Sons 和 Wrox Press出版社写书。

关于译者

Cocia Lin(cocia@163.com)是程序员。它拥有学士学位,现在专攻Java相关技术,刚刚开始在计算机领域折腾。

相关资源

You'll find the speech engine and related source code in the jw-0817-javatalk.zip file:
http://www.javaworld.com/jw-08-2001/javatalk/jw-0817-javatalk.zip
Go to java.sun.com's "Java Sound API" page for documentation, DOWNLOAD information, and FAQ:
http://java.sun.com/products/java-media/sound/
To see how the speech engine will combine with Webpages to build my talking browser, read "Access the World's Biggest Database with Web Database Connectivity," Tony Loton (JavaWorld, March 2001):
db.html">http://www.javaworld.com/javaworld/jw-03-2001/jw-0316-webdb.html
In "Make an EJB from Any Java Class with Java Reflection" (JavaWorld, December 2000), Tony Loton explains how to turn any Java class into an EJB, and any single-tier Java application into an enterprise application:
http://www.javaworld.com/jw-12-2000/jw-1215-anyclass.html
"Program Multimedia with JMF," Budi Kurniawan (JavaWorld):
Part 1: Go multimedia by learning how the Java Media framework compares to your stereo system (April 2001)
Part 2: Jump into Java Media Framework's important classes and interfaces (May 2001)
"Add mp3 capabilities to Java Sound with SPI," Dan Becker (JavaWorld, November 2000):
http://www.javaworld.com/jw-11-2000/jw-1103-mp3.html
Sign up for the JavaWorld This Week free weekly email newsletter to learn what's new at JavaWorld:
http://www.idg.net/jw-subscribe
You'll find a wealth of IT-related articles from our sister publications at IDG.net
 


 


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

让Java说话! (转)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

让Java说话! (转)

让Java说话! (转)[@more@] 让Java说话! 为你的Java 1.3 应用程序和Applet添加说话能力概要这篇文章中,Tony Loton展示了不使用硬件和本地调用的,少于150行Java代码实现一个简单的语音引擎。此外,
2023-06-03

Python数据分析:让数据为你说话

Python数据分析是一个强大的工具,可以帮助你从复杂的数据中提取有价值的见解。本文将介绍Python中用于数据分析的关键工具和技术,并提供示例代码,让你体验它们的强大功能。
Python数据分析:让数据为你说话
2024-02-17

怎么使用JavaScript让你的浏览器说话

这篇文章主要介绍怎么使用JavaScript让你的浏览器说话,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!javascript是一种什么语言javascript是一种动态类型、弱类型的语言,基于对象和事件驱动并具有相
2023-06-14

让代码说话:PHPDoc 文档的实战指南

PHPDoc 是一种文档注释标准,使用户能够通过注释对 PHP 代码进行详细记录。本指南提供了使用 PHPDoc 进行注释的实战建议,帮助您编写更具可维护性和可读性的代码。
让代码说话:PHPDoc 文档的实战指南
2024-02-29

ASP 操作筛选器的魔法:让数据说话

ASP 操作筛选器的魅力:让数据栩栩如生
ASP 操作筛选器的魔法:让数据说话
2024-02-15

Java中文乱码解决方案全解析,让你的程序“说人话”!

Java中文乱码解决方案全解析旨在解决程序输出中文乱码问题。乱码成因主要有字符集不匹配、字节流编码错误和操作系统设置不一致。解决方案包括:设定兼容的中文字符集(如UTF-8)、正确编码字节流(使用标准编码器如StandardCharsets.UTF_8)、确保操作系统和Java运行环境字符集设置一致。具体实现方法包括:文件读写时指定字符集、数据库连接时配置字符集、Web开发中设置请求和响应字符集。注意保持字符集一致性,优先使用UTF-8字符集,并及时更新Java运行环境。
Java中文乱码解决方案全解析,让你的程序“说人话”!
2024-04-02

数据库OLAP:让数据说话,洞悉商业未来

: 数据库OLAP(联机分析处理)通过多维数据分析,帮助企业快速提取数据洞察,为决策提供依据。本文将探讨OLAP技术原理并提供Python演示代码,帮助企业充分利用数据。
数据库OLAP:让数据说话,洞悉商业未来
2024-02-12

NumPy统计分析宝典:让数据说话的大师之作

NumPy是Python中用于统计分析和数据处理的强大库,本文将向您展示如何使用NumPy进行各种统计分析操作,让您轻松从数据中提取洞察力。
NumPy统计分析宝典:让数据说话的大师之作
2024-02-11

利用VUE D3.js和Vue.js打造惊艳的数据可视化效果:让数据说话

: 随着数据成为企业的重要资产,高效地可视化数据以提取有价值的见解变得尤为关键。本文将探讨如何结合Vue.js和D3.js的力量,创建引人入胜的数据可视化效果,让数据以一种更生动和直观的方式说话。 : 数据可视化、Vue.js、D3.js、数据图表、数据分析 前言: 在当今信息爆炸的时代,数据已成为企业的重要资产。为了从这些大量数据中提取有价值的见解,数据可视化成为了一种必不可少的工具。数据可视化能够将复杂的数据转化为易于理解的图形与图表,帮助人们快速掌握关键信息,做出明智的决策。
利用VUE D3.js和Vue.js打造惊艳的数据可视化效果:让数据说话
2024-02-27

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录