采样包概述

javax.sound.sampled包从根本上关系到音频传输-换句话说,Java Sound API 专注于回放和catch。 Java Sound API 解决的中心任务是如何将格式化音频数据的字节移入和移出系统。此任务涉及打开音频 Importing 和输出设备,以及 管理 填充有实时声音数据的缓冲区。它还可能涉及将多个音频流混合到一个流中(无论是 Importing 还是输出)。当用户请求启动,暂停,恢复或停止声音流时,必须正确处理声音进出系统的问题。

为了支持对基本音频 Importing 和输出的关注,Java Sound API 提供了在各种音频数据格式之间进行转换以及读取和写入常见类型的声音文件的方法。但是,它并不试图成为一个全面的声音文件工具箱。 Java Sound API 的特定实现不需要支持大量的文件类型或数据格式转换。第三方服务提供商可以提供“插入”现有实现的模块,以支持其他文件类型和转换。

Java Sound API 可以以流式,缓冲方式和内存中,非缓冲方式处理音频传输。在一般意义上,“流”是指音频字节的实时处理。它不涉及通过 Internet 以某种格式发送音频的特定的众所周知的情况。换句话说,音频流只是一组连续的音频字节,它们或多或少以与处理(播放,录制等)它们相同的速率到达。在所有数据到达之前就开始对字节进行操作。在流模型中,尤其是在音频 Importing 而不是音频输出的情况下,您不必事先知道声音多 Long 时间以及何时结束到达。您只需一次处理一个音频数据缓冲区,直到操作停止。对于音频输出(播放),如果要播放的声音太大而无法一次全部存储在内存中,则还需要缓冲数据。换句话说,您将音频字节以块的形式传递给声音引擎,并且它会在正确的时间播放每个 samples。提供的机制使您很容易知道每个块中要传送多少数据。

Java Sound API 还仅在回放的情况下允许无缓冲传输,前提是您已经手头上有所有音频数据,并且它不会太大而无法容纳在内存中。在这种情况下,虽然如果需要,仍然可以使用缓冲的实时方法,但应用程序无需缓冲音频。取而代之的是,整个声音可以立即预加载到内存中,以便随后播放。由于所有声音数据都是预先加载的,因此可以立即开始播放-例如,只要用户单击“开始”按钮即可。与缓冲模型相比,这是一个优势,在缓冲模型中,回放必须 await 第一个缓冲区填满。此外,内存中无缓冲模型使声音可以轻松循环(循环)或设置为数据中的任意位置。

要使用 Java Sound API 播放或catch声音,您至少需要三件事:格式化的音频数据,混音器和一行。以下概述了这些概念。

什么是格式化音频数据?

格式化的音频数据是指多种标准格式中的任何一种声音。 Java Sound API 区分数据格式文件格式

Data Formats

数据格式告诉您如何解释“原始”采样音频数据的一系列字节,例如已从声音文件中读取的 samples 或已从麦克风 Importing catch的 samples。例如,您可能需要知道多少个位构成一个采样(声音的最短瞬间的表示),并且类似地,您可能需要知道声音的采样率(采样应遵循的速度有多快)。设置播放或catch时,可以指定要catch或播放的声音的数据格式。

在 Java Sound API 中,数据格式由AudioFormat对象表示,该对象包含以下属性:

  • 编码技术,通常是脉冲编码调制(PCM)

  • Channels 数(单声道 1,立体声 2 等)

  • 采样率(每个通道每秒的采样数)

  • 每个 samples 的位数(每个通道)

  • Frame rate

  • 帧大小(以字节为单位)

  • 字节 Sequences(大端或小端)

PCM 是声音波形的一种编码。 Java Sound API 包括两种 PCM 编码,它们使用振幅的线性量化以及有符号或无符号整数值。线性量化意味着存储在每个 samples 中的数字与该瞬间的原始声压成正比(除任何失真外),并且与该 Moment 随声音振动的扬声器或鼓膜的位移成正比。例如,光盘使用线性 PCM 编码的声音。 Mu-law 编码和 a-law 编码是常见的非线性编码,可提供音频数据的更多压缩版本。这些编码通常用于电话或语音记录。非线性编码使用非线性函数将原始声音的幅度 Map 到存储的值,该函数可以设计成为安静的声音提供比大声声音更大的幅度分辨率。

帧包含特定时间所有通道的数据。对于 PCM 编码的数据,该帧只是给定时间瞬间所有通道中同时采样的集合,而没有任何其他信息。在这种情况下,帧速率等于采样率,以字节为单位的帧大小是通道数乘以以位为单位的采样大小,再除以字节中的位数。

对于其他类型的编码,一帧可能除了采样之外还包含其他信息,并且帧速率可能与采样速率完全不同。例如,考虑 MP3(MPEG-1 音频第 3 层)编码,该编码在当前版本的 Java Sound API 中没有明确提及,但 Java Sound API 的实现或第三方可以支持该编码。服务提供者。在 MP3 中,每个帧包含一束用于一系列采样的压缩数据,而不仅仅是每个通道一个采样。由于每个帧封装了整个 samples 序列,因此帧速率比采样速率慢。该框架还包含一个标题。尽管有 Headers,但以字节为单位的帧大小小于相等数量的 PCM 帧的以字节为单位的大小。 (毕竟,MP3 的 Object 是要比 PCM 数据更紧凑.)对于这种编码,采样率和 samples 大小是指 PCM 数据,编码后的声音final将被转换成这种数字,然后再传递给数字音频。模数转换器(DAC)。

File Formats

文件格式指定了声音文件的结构,不仅包括文件中原始音频数据的格式,还包括可以存储在文件中的其他信息。声音文件有各种标准品种,例如 WAVE(也称为 WAV,通常与 PC 关联),AIFF(通常与 Macintoshes 关联)和 AU(通常与 UNIX 系统关联)。不同类型的声音文件具有不同的结构。例如,它们在文件的“标题”中可能具有不同的数据排列方式。Headers 包含通常在文件实际音频 samples 之前的描述性信息,尽管某些文件格式允许描述性和音频数据的连续“块”。Headers 包含用于将音频存储在声音文件中的数据格式的规范。这些声音文件中的任何一种都可以包含各种数据格式(尽管通常在给定文件中只有一种数据格式),并且可以在具有不同文件格式的文件中使用相同的数据格式。

在 Java Sound API 中,文件格式由AudioFileFormat对象表示,该对象包含:

  • 文件类型(WAVE,AIFF 等)

  • 文件的 Long 度(以字节为单位)

  • 文件中包含的音频数据的 Long 度(以帧为单位)

  • AudioFormat 对象,它指定文件中包含的音频数据的数据格式

AudioSystem类提供用于读取和写入不同文件格式的声音以及在不同数据格式之间进行转换的方法。一些方法使您可以通过称为AudioInputStream的流访问文件的内容。 AudioInputStreamInputStream类的子类,它封装了可以 Sequences 读取的一系列字节。 AudioInputStream类为其父类增加了有关字节的音频数据格式(由AudioFormat对象表示)的知识。通过将声音文件读取为AudioInputStream,您可以立即访问 samples,而不必担心声音文件的结构(其 Headers,块等)。单个方法调用为您提供了有关数据格式和文件类型的所有所需信息。

什么是调音台?

许多声音的应用程序编程interface(API)都使用音频* device *的概念。设备通常是物理 Importing/输出设备的软件interface。例如,声音 Importing 设备可能代表了声卡的 Importing 功能,包括麦克风 Importing,线路电平模拟 Importing 以及数字音频 Importing。

在 Java Sound API 中,设备由Mixer对象表示。混合器的 Object 是处理一个或多个音频 Importing 流和一个或多个音频输出流。在典型情况下,它实际上将多个传入流混合在一起成为一个传出流。 Mixer对象可以表示诸如声卡之类的物理设备的混音功能,可能需要混合从各种 Importing 进入计算机的声音,或从应用程序进入输出的声音。

或者,Mixer对象可以表示完全在软件中实现的混音功能,而没有与物理设备的任何固有interface。

在 Java Sound API 中,诸如声卡上的麦克风 Importing 之类的组件本身并不被视为设备(即调音台),而是被视为进入或离开调音台的“端口”。端口通常会向混音器中或从混音器中提供单个音频流(尽管该流可以是多声道的,例如立体声)。混合器可能有几个这样的端口。例如,代表声卡输出功能的混音器可能将几个音频流混合在一起,然后将混合后的 signal 发送到连接到混音器的各种输出端口中的任何一个或全部。这些输出端口可以是(例如)耳机插孔,内置扬声器或线路电平输出。

要了解 Java Sound API 中混音器的概念,它有助于可视化物理混音控制台,例如在 site 音乐会和录音室中使用的那些。

以下上下文描述了此图。

物理调音台

物理混频器具有“条”(也称为“切片”),每个条均表示一条路径,单个音频 signal 通过该路径进入混频器进行处理。试条具有旋钮和其他控件,通过它们可以控制该试条中 signal 的音量和声相(在立体声图像中的放置)。而且,混音器可能具有单独的总线来实现混响等效果,并且该总线可以连接到内部或外部混响单元。每个条带都有一个电位器,用于控制该条带 signal 中有多少进入混响混音。然后将混响的(“湿”)混合物与来自条的“干”signal 混合。物理混合器将此final混合物发送到输出总线,该输出总线通常到达磁带录音机(或基于磁盘的录音系统)和/或扬声器。

想象以立体声录制的 site 音乐会。来自舞台上许多麦克风和电子乐器的电缆(或无线连接)插入到调音台的 Importing 中。如图所示,每个 Importing 都进入混频器的单独条带。声音工程师决定增益,声相和混响控件的设置。所有条带的输出和混响单元被混合在一起成为两个通道。这两个通道到达混音器上的两个输出,电缆插入其中,并连接到立体声磁带录音机的 Importing。根据音乐类型和大厅的大小,这两个通道也可能通过放大器发送到大厅的扬声器。

现在想象一下一个录音室,其中的每个乐器或歌手都被录制到多轨录音机的单独轨道上。乐器和歌手全部录制完毕后,录音工程师执行“混音”操作,将所有录音带组合成一个两通道(立体声)录音,然后将其分发到光盘上。在这种情况下,每个混音器条的 Importing 不是麦克风,而是多轨录音的一个轨。再一次,工程师可以使用控制条上的控件来确定每个音轨的音量,声像和混响量。调音台的输出再次转到立体声录音机和立体声扬声器,如 site 音乐会的示例所示。

这两个示例说明了混音器的两种不同用法:catch多个 Importing 通道,将它们组合成更少的轨道,并保存混合,或者播放多个轨道,同时将它们混合成更少的轨道。

在 Java Sound API 中,混合器可以类似地用于 Importing(catch音频)或输出(播放音频)。对于 Importing,混音器从中获取音频进行混音的* source 是一个或多个 Importing 端口。混合器将catch的和混合的音频流发送到其 target *,该对象是带有缓冲区的对象,应用程序可以从该对象检索此混合音频数据。如果是音频输出,则情况相反。调音台的音频源是一个或多个对象,这些对象包含一个或多个应用程序在其中写入其声音数据的缓冲区。调音台的目标是一个或多个输出端口。

什么是线?

物理混合控制台的隐喻对于理解 Java Sound API 的* line *概念也很有用。

线是数字音频“管道”的元素,即用于将音频移入或移出系统的路径。通常,管线是进入或流出混合器的路径(尽管从技术上讲,混合器本身也是一种管线)。

音频 Importing 和输出端口是线路。这些类似于连接到物理调音台的麦克风和扬声器。另一类线路是数据路径,应用程序可通过该数据路径从混音器获取 Importing 音频或将输出音频发送到混音器。这些数据路径类似于连接到物理调音台的多轨录音机的轨道。

Java Sound API 中的行与物理混音器中的行之间的区别是流过 Java Sound API 中的行的音频数据可以是单声道或多声道(例如,立体声)。相比之下,物理混音器的每个 Importing 和输出通常是单个声音通道。为了从物理混音器获得两个或多个通道的输出,通常使用两个或多个物理输出(至少在模拟声音的情况下;数字输出插孔通常是多通道的)。在 Java Sound API 中,一行中的通道数由当前流经该行的数据的AudioFormat指定。

现在让我们研究一些特定种类的线路和混合器。下图显示了简单的音频输出系统中不同类型的线路,这些线路可能是 Java Sound API 实现的一部分:

以下上下文描述了此图。

音频输出线的可能配置

在此示例中,应用程序可以访问音频 Importing 混音器的一些可用 Importing:一个或多个* clips source 数据线*。片段是混音器 Importing(一种行),您可以在播放之前将音频数据加载到其中。源数据线是混音器 Importing,它接受音频数据的实时流。应用程序将声音文件中的音频数据预加载到片段中。然后,它将其他音频数据推入源数据线,一次放入一个缓冲区。混音器从所有这些线路读取数据,每条线路可能都有自己的混响,增益和声像控制,并将干音频 signal 与湿混响混合。混音器将其final输出传递到一个或多个输出端口,例如扬声器,耳机插孔和线路输出插孔。

尽管图中各条线被描绘为单独的矩形,但它们都是混频器“拥有”的,可以视为混频器的组成部分。混响,增益和声像矩形代表混音器可以应用到流经这些行的数据的处理控件(而不是行)。

请注意,这只是 API 支持的一种可能的混合器的示例。并非所有音频配置都具有所示的所有功能。单个源数据行可能不支持平移,混音器可能未实现混响,等等。

一个简单的音频 Importing 系统可能类似于:

以下上下文描述了此图

音频 Importing 线的可能配置

此处,数据从一个或多个 Importing 端口(通常是麦克风或 Importing 插孔)流入混频器。应用增益和声相,并且混频器通过混频器的目标数据线将catch的数据传递到应用程序。目标数据线是混音器输出,其中包含流 Importing 声音的混合。最简单的混合器只有一条目标数据线,但是有些混合器可以将catch的数据同时传送到多条目标数据线。

线路interface层次结构

现在,我们已经看到了有关行和混频器的一些功能图片,让我们从更具编程性的角度进行讨论。基本Lineinterface的子interface定义了几种类型的线。interface层次结构如下所示。

以下上下文描述了此图

线路interface层次结构

基本interfaceLine描述了所有行共有的最小功能:

  • 控件–数据线和端口通常具有一组控件,这些控件会影响通过该线的音频 signal。 Java Sound API 指定了可用于处理声音各方面的控制类,例如:增益(影响 signal 的分贝数),声相(影响声音的左右位置,混响(将混响添加到声音)模拟不同种类的室内声学)和采样率(这会影响播放速率以及声音的音高)。

  • 打开或关闭状态–成功打开线路可确保已将资源分配给该线路。混合器的行数是有限的,因此有时可能会争用多个应用程序(或同一个应用程序)以使用混合器的线。关闭一行表示该行使用的任何资源现在都可以释放。

  • 事件–一行打开或关闭时都会生成事件。 Line的子interface可以引入其他类型的事件。当一行生成一个事件时,该事件将发送到已注册为“侦听”该行上的事件的所有对象。应用程序可以创建这些对象,注册它们以侦听线路事件,并根据需要对事件做出反应。

现在,我们将检查Lineinterface的子interface。

Ports是用于将音频 Importing 到音频设备或从音频设备输出音频的简单行。如前所述,一些常见的端口类型是麦克风,线路 Importing,CD-ROM 驱动器,扬声器,耳机和线路输出。

Mixerinterface代表混合器,当然,正如我们所见,它代表硬件或软件设备。 Mixerinterface提供用于获取混音器线路的方法。其中包括将音频 Importing 到混合器的源线和混合器将其混合音频传递到的目标线。对于音频 Importing 混音器,源线是诸如麦克风 Importing 之类的 Importing 端口,目标线是TargetDataLines(如下所述),这些音频将音频传送到应用程序。另一方面,对于音频输出混合器,源线是ClipsSourceDataLines(如下所述),应用程序向其馈送音频数据,并且目标线是诸如扬声器的输出端口。

A Mixer被定义为具有一条或多条源线和一条或多条目标线。请注意,此定义意味着混合器实际上不需要混合数据。它可能只有一条源代码行。 Mixer API 旨在包含各种设备,但典型情况下支持混合。

Mixerinterface支持同步;也就是说,您可以指定将两个或更多混音器的线路视为同步组。然后,您可以通过向组中的任何一行发送一条消息来启动,停止或关闭所有这些数据行,而不必分别控制每一行。使用支持此功能的混音器,您可以在行之间获得精确到 samples 的同步。

通用Lineinterface没有提供开始和停止播放或记录的方法。为此,您需要一条数据线。 DataLineinterface提供了Line以外的其他与媒体相关的功能:

  • 音频格式–每条数据线都有与其数据流相关联的音频格式。

  • 介质位置–数据行可以报告其在介质中的当前位置,以 samples 帧表示。这表示自数据线打开以来从数据线catch或呈现的 samples 帧数。

  • 缓冲区大小–这是数据线内部缓冲区的大小(以字节为单位)。对于源数据线,内部缓冲区是可以向其写入数据的缓冲区,对于目标数据线,内部缓冲区是可以从其读取数据的缓冲区。

  • 电平(音频 signal 的当前幅度)

  • 开始和停止播放或catch

  • 暂停并 continue 播放或catch

  • 刷新(从队列中丢弃未处理的数据)

  • 清空(阻塞,直到所有未处理的数据从队列中清空,并且数据行的缓冲区变空)

  • 活动状态–如果数据线参与主动向音频混音器演示或从混音器捕捉音频数据,则该数据线被认为是活动的。

  • 事件–当主动演示或catch数据行或从数据行catch数据时,会产生STARTSTOP事件。

TargetDataLine从混音器接收音频数据。通常,调音台已从麦克风等端口catch了音频数据。在将数据放入目标数据线的缓冲区之前,它可能会处理或混合catch的音频。 TargetDataLineinterface提供了用于从目标数据行的缓冲区读取数据以及确定当前有多少数据可读取的方法。

A SourceDataLine接收音频数据以进行播放。它提供了将数据写入源数据行的缓冲区以进行回放,以及确定该行准备接收多少数据而不会阻塞的方法。

A Clip是一条数据线,可以在播放之前将音频数据加载到其中。由于数据是预加载的而不是流式传输的,因此在播放之前会知道剪辑的持续时间,您可以选择媒体中的任何起始位置。剪辑可以循环播放,这意味着在播放时,两个指定循环点之间的所有数据将重复指定次数或无限期重复。

本节介绍了采样音频 API 的大多数重要interface和类。随后的部分说明如何在应用程序中访问和使用这些对象。