前言:今天早上突发奇想想要玩一玩Java自带的声音API,闲着无聊学了一下午搞明白了它的用法(没有视频光看文字果然学习效率低下)
本来其实想做一个实时翻译的功能,用Aliyun的API,但是阿里云的API好像要付费,虽然GitHub上有做好的DEMO了,还挺好,自带字幕在屏幕底部,但是没有买套餐包,所以没法用,太难了。
然后闲着无聊想要搞一个耳机返听麦克风功能,听到自己的环境音,所以Bing了各种问题,敲敲打打缝缝补补搞出来一个DEMO,想要测试的时候发现,我电脑麦克风坏了你能信,插耳机或者笔记本自带的音响都没法用,佛了,虽然做出来了,逻辑上觉得还可以,应该没啥问题,但是估计跑起来有问题吧。有空了再去修一修。
在这里立下一个介绍(浅谈)javax.sound相关包的适用方法教程博文的Flag,有空一定!
——2020 05-17 17:23
时隔几天,我又回来了。开始更新。我可真是鸽子?
——2020 05-23 08:13
如何通过Java原生API录制音频?
要录制音频之前,我们要先认识一下AudioFormat
这个类,
AudioFormat (Java Platform SE 8 )AudioFormat
类适用于多种常见的声音文件编码技术,包括脉码调制(PCM),多律法编码和法律编码。 这些编码技术是预定义的,但服务提供商可以创建新的编码类型。 特定格式使用的编码由其encoding
字段命名。
这个类是用来定义音频文件的格式的,比如说:采样频率,双声道,位数等。接下来列出来一个比较简单的写好的getAudioFormat()
方法
public static AudioFormat getAudioFormat(){ //下面注释部分是另外一种音频格式,两者都可以 AudioFormat.Encoding encoding = AudioFormat.Encoding. PCM_SIGNED ; float rate = 8000f;//采样频率 int sampleSize = 16;//表示每个具有此格式的声音样本中的位数 String signedString = "signed"; boolean bigEndian = true; int channels = 1;//单声道 return new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian);//返回一个创建好的AudioFormat类 // //采样率是每秒播放和录制的样本数 // float sampleRate = 16000.0F; // // 采样率8000,11025,16000,22050,44100 // //sampleSizeInBits表示每个具有此格式的声音样本中的位数 // int sampleSizeInBits = 16; // // 8,16 // int channels = 1; // // 单声道为1,立体声为2 // boolean signed = true; // // true,false // boolean bigEndian = true; // // true,false // return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,bigEndian); } public static InputStream streamTran(ByteArrayOutputStream baos) {//输出流转换成输入流工具 return new ByteArrayInputStream(baos.toByteArray()); }
有了AudioFormat
之后,我们就可以根据我们设置好的声音参数来采集声音了。
public static ByteArrayOutputStream out = new ByteArrayOutputStream();//写出流 public void record() { try { AudioFormat format = AudioUtils.getAudioFormat();//获取需要采样声音的参数信息 DataLine.Info info = new DataLine.Info(TargetDataLine.class,format); // format is an AudioFormat object TargetDataLine line = (TargetDataLine)(AudioSystem.getLine(info));//获取与指定的Line.Info对象中的描述匹配的行。 //通俗点就是获取一下话筒Line line.open(format);//以指定的格式打开行,使该行获取任何所需的系统资源,并可以运行。 /* *****这里的DataLine等操作,可以直接CV拷贝,这些都是固定格式。***** */ // Assume that the TargetDataLine, line, has already // been obtained and opened. int numBytesRead; byte[] data = new byte[line.getBufferSize() / 5];//设置缓冲区大小 // Begin audio capture. line.start();//开始记录声音 //允许线路从事数据I / O。 如果在已经运行的行上调用该方法,该方法什么也不做。 除非缓冲区中的数据已被刷新, //否则线路将从线路停止时未处理的第一帧开始恢复I / O。 当音频捕获或播放开始时,会生成一个START事件。 // Here, stopped is a global boolean set by another thread. for(;;) {//这里设置成为死循环,方便一直记录,不停歇。 // Read the next chunk of data from the TargetDataLine. numBytesRead = line.read(data, 0, data.length);//读取字节到字节数组 // Save this chunk of data. out.write(data, 0, numBytesRead);//写出流 } } catch (LineUnavailableException e) { e.printStackTrace(); } }
什么是
DataLine.Info (Java Platform SE 8 )DataLine.Info
?
除了从其超类继承的类信息,DataLine.Info
还提供了特定于数据行的附加信息。 此信息包括: 数据线支持的音频格式
其内部缓冲区的最小和最大大小
因为一个Line.Info
知道类其描述了线,一个DataLine.Info
对象可以描述DataLine
子接口,如,
SourceDataLine
和
TargetDataLine
。 可以查询的任何这些类型的线混合器,传递的适当实例
Clip
DataLine.Info
作为参数的方法,如。
Mixer.getLine(Line.Info)
什么是
TargetDataLine (Java Platform SE 8 )TargetDataLine
?
目标数据线是可读取音频数据的类型
DataLine
。 最常见的示例是从音频捕获设备获取其数据的数据线。 (该设备实现为写入目标数据线的混音器。)
DataLine
目标数据线可以通过调用具有适当的对象的
DataLine.Info
Mixer
的方法从混合器获得。
getLine
写好这写代码之后,就可以在out
流中读取到捕捉的音频字节了!
如何播放音频?
private InputStream is = null; public void play() { is = (ByteArrayInputStream) AudioUtils.streamTran(RecordVoice.out); SourceDataLine sdl = null; try { DataLine.Info info = new DataLine.Info(SourceDataLine.class, AudioUtils.getAudioFormat()); sdl = (SourceDataLine) AudioSystem.getLine(info);//获取音频输出的Line sdl.open(AudioUtils.getAudioFormat()); sdl.start(); byte[] buffer = new byte[1024];//缓存数组 int temp = 0; while(true) { temp = is.read(buffer);//读取字节 //(temp = inputStream.read(buffer))>=0 try { sdl.write(buffer, 0, temp);//写出播放到音响的Line里。 }catch(Exception e1) {updateIs();continue;}//如果流里没有东西了,就手动更新一下 //输出声音 updateIs(); //每一次都重新获取一下声音流 } } catch (Exception e) { e.printStackTrace(); }finally { sdl.drain(); sdl.close(); } }
什么是
SourceDataLine (Java Platform SE 8 )SourceDataLine
?
源数据线是可以写入数据的数据线。 它作为混音器的源头。 应用程序将音频字节写入源数据线,该数据线处理字节的缓冲并将其传递到混频器。 混合器可以将样品与来自其他来源的样品混合,然后将混合物输送到目标,例如输出端口(其可以表示声卡上的音频输出设备)。
可以通过调用具有适当的对象的
DataLine.Info
Mixer
的方法从混合器获得源数据线。
getLine
这样,我们就简单的实现了一个声音的录制/播放功能。