Java Sound教程(1)

声明Java Sound教程系列属于Sun MicrosystemJava Tutorials,由kingmmxtj2008115日开始翻译,并将在http://hi.baidu.com/kingmmxtj上发布。译者尊重Sun的权利,仅仅把文章用于学习交流。转贴请保留,谢谢!

原文地址http://java.sun.com/docs/books/tutorial/sound/index.html

Sound开始

Java Sound API是一种低级的API,用来处理和控制声音媒体的输入和输出。声音媒体包括了音频数据和乐器数字化接口数据(MIDI)。Java Sound API针对声音输入和输出通常所要求的性能提供了显式控制,并提供了一种提高扩展性和灵活性的框架。

Java Sound API实现了应用程序开发者的广泛需求。可能的应用程序领域包括:

l         通信架构程序,例如会议和电话技术

l         最终用户数据传递系统,例如媒体播放器和使用流格式的音乐

l         互动性的应用程序,例如游戏和使用动态内容的网站

l         数据流创造和编辑

l         开发工具,工具包,和实用程序

Java Sound API提供Java平台下最底层的声音支持,它提供应用程序大量针对声音操作的控制,并且这都是可以扩展的。例如,Java Sound API提供安装、访问、和操控系统资源的各种机制,像音频混频器(mixer)、MIDI合成器(synthesizer),或者其他的音频和MIDI设备、文件读取器(reader)、文件写入器(writer)、声音格式转换器(converter)。Java Sound API不包括复杂的声音编辑器或者图形化工具,但是它提供了建立这些应用的能力。Java Sound API强调的是大部分最终用户都所期望的对声音的底层控制。

Java Sound API包括了对数字音频和MIDI数据的支持。这2个主要模块的功能在以下独立的包内:

l         javax.sound.sampled

该包详细描绘了对数字(采样)音频的捕捉(capture)、混音(mixing),回放(playback)的各种接口。

l         javax.sound.midi

该包提供了MIDI合成(synthesis),序列化(sequencing),事件传输(event transport)等接口。

另外2个包允许服务提供者(service providers)(与应用程序开发者相对而言)创建自定义的软件组件,来扩展某种Java Sound API具体实现的功能:

l         javax.sound.sampled.spi

l         javax.sound.midi.spi

本页介绍了采样音频系统、MIDI系统,SPI包。每一个包将在后续章节中进行详细介绍。

―――――――――――――――――――――――――――――――――――――――

注意:Java平台的某些APIs也有与声音相关的。Java Media Framework API (JMF)是一种高级API,现在作为Java平台的一种标准扩展。JMF详细描绘了一个统一的架构、消息协议、和捕捉、回放以时间为基准的媒体的编程接口。 JMF提供了一种针对基本媒体播放器应用程序的简单解决方案, 同样也允许不同媒体类型之间的同步,如音频和时频的同步。另一方面,集中于声音处理的程序可以从Java Sound API中获得便利,特别是那些需要更多高级特性的程序,像微调控制缓存音频回放的能力或者直接操控一台MIDI合成器。其他与声音相关的Java APIs包括Java 3D、电话技术和语音的APIs。所有上述的这些与声音相关的APIs的某种实现都可能在其内部用到某个Java Sound API的实现,但这不是必须的。

―――――――――――――――――――――――――――――――――――――――

什么是采样音频?

javax.sound.sampled包处理数字音频数据,这种数据在Java Sound API里即为采样音频。采样是对一个信号的连续快照(snapshots)。对音频而言,信号就是一段声波。麦克风把原始的信号转化为相关的模拟电信号,然后AD转换器把该模拟信号转化为一种采样的数字信号。下图为声音录制中的一小段时间。

一段采样的音频波形

该图在纵轴上画出了声波的幅度,水平轴为时间。该模拟声波的幅度在某个频率下等间隔的被测量,最后形成的离散采样点(图中的红色数据点)组成了数字音频信号。图中中间的水平线代表幅度为0;线上的点为正值采样点,线下的为负值。数字信号逼近某个模拟信号的精度取决于其在时间上的分辨率(采样频率)和其量化标准(幅度上的分辨率,每个采样点用几位数字来表示)。作为一个例子,CD上存储的音频数据是每秒采样44100个点、用16位的数字来表示每个采样点的数值。

“采样音频”(sampled audio)这个术语在这里比较宽泛。一个声波可以按照一个离散间隔来采样但仍然保留其模拟信号的形式。然而在Java Sound API里,“采样音频”的意思就是“数字音频”(digital audio)。

特别需要注意的是,电脑上的采样音频来自于声音录制,但是相应的声音也可以由各种其他声音信号合成的(例如合成一个拨号电话的声音)。“采样音频”在这儿指的就是这种合成性的声音,而不是原始的声音信号。

Java Sound API并不针对某种音频硬件配置;它被设计成允许不同音频组件安装在系统上并且都可以被API访问。Java Sound API支持常用的功能,像声卡的输入和输出(例如声音文件的录制和回放)及多种音频流的混响。下图是典型音频系统架构示意图:

 

一个典型音频系统架构

在这个图中,像声卡这种设备有许多的输入和输出端口,而混响则由软件提供。混频器可能通过读取一个文件、网络上的流,应用程序产生的数据、及MIDI合成器产生的文件来接收数据。混频器把音频输入的各种信号组合成一个单一的流,该流可以被送到输出设备进行输出。

转载于:https://my.oschina.net/baobao/blog/13044

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 Java 代码示例,可以使用降噪算法来处理音频文件。这个示例使用了一个名为“SpectralSubtraction”的算法,它将信号的频谱进行分析,并且从中剔除噪声。这个算法需要一些音频处理的基础知识,但是代码本身并不复杂。 首先,你需要导入 Java 的音频处理库: ``` import javax.sound.sampled.*; ``` 然后,你可以使用以下代码来读取你想要处理的音频文件: ``` AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("input.wav")); ``` 其中,"input.wav" 是你要读取的音频文件的路径。 接下来,你需要定义一些常量。这些常量将会影响你的降噪算法的效果。例如,你可以根据需要修改采样率、窗口大小和噪声门限等参数。 ``` final int sampleRate = 16000; final int windowSize = 512; final int hopSize = 256; final double noiseThreshold = 0.15; ``` 然后,你可以使用以下代码来进行降噪处理: ``` // 读取音频数据 byte[] audioBytes = new byte[(int) (audioInputStream.getFrameLength() * audioInputStream.getFormat().getFrameSize())]; audioInputStream.read(audioBytes); // 将字节数组转换为采样数组 double[] audioSamples = new double[audioBytes.length / 2]; for (int i = 0; i < audioSamples.length; i++) { audioSamples[i] = ((short) ((audioBytes[i * 2] & 0xff) | (audioBytes[i * 2 + 1] << 8))) / 32768.0; } // 计算频谱 FFT fft = new FFT(windowSize); int numFrames = (audioSamples.length - windowSize) / hopSize + 1; double[][] frames = new double[numFrames][windowSize]; for (int i = 0; i < numFrames; i++) { for (int j = 0; j < windowSize; j++) { frames[i][j] = audioSamples[i * hopSize + j]; } fft.forward(frames[i]); } // 计算噪声门限 double[] spectrum = new double[windowSize / 2 + 1]; double[] noiseThresholds = new double[spectrum.length]; for (int i = 0; i < spectrum.length; i++) { double sum = 0.0; for (int j = 0; j < numFrames; j++) { double magnitude = Math.sqrt(frames[j][2 * i] * frames[j][2 * i] + frames[j][2 * i + 1] * frames[j][2 * i + 1]); spectrum[i] += magnitude / numFrames; if (magnitude > noiseThreshold) { sum += 1.0; } } noiseThresholds[i] = (sum / numFrames) * noiseThreshold; } // 进行降噪 for (int i = 0; i < numFrames; i++) { for (int j = 0; j < windowSize / 2 + 1; j++) { double magnitude = Math.sqrt(frames[i][2 * j] * frames[i][2 * j] + frames[i][2 * j + 1] * frames[i][2 * j + 1]); if (magnitude < noiseThresholds[j]) { frames[i][2 * j] = 0.0; frames[i][2 * j + 1] = 0.0; } } fft.inverse(frames[i]); } // 合并所有帧 double[] denoisedSamples = new double[(numFrames - 1) * hopSize + windowSize]; for (int i = 0; i < numFrames; i++) { for (int j = 0; j < windowSize; j++) { if (i == 0) { denoisedSamples[j] = frames[i][j]; } else { denoisedSamples[i * hopSize + j] += frames[i][j]; } } } // 将采样数组转换为字节数组 byte[] denoisedBytes = new byte[audioBytes.length]; for (int i = 0; i < denoisedSamples.length; i++) { short sample = (short) (denoisedSamples[i] * 32768.0); denoisedBytes[i * 2] = (byte) (sample & 0xff); denoisedBytes[i * 2 + 1] = (byte) (sample >> 8); } // 将降噪后的音频数据写入文件 AudioFormat audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(denoisedBytes); AudioInputStream denoisedAudioInputStream = new AudioInputStream(byteArrayInputStream, audioFormat, denoisedBytes.length / audioFormat.getFrameSize()); AudioSystem.write(denoisedAudioInputStream, AudioFileFormat.Type.WAVE, new File("output.wav")); ``` 其中,"output.wav" 是处理后的音频文件的路径。 这个示例中的降噪算法只是其中一种,你可以根据需要使用其他算法。请注意,音频处理是一个非常复杂的领域,需要深入的知识和经验才能取得好的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值