手动更改扬声器位置

Manually Change Speaker Position

除非我弄错了,否则扬声器由具有多个位置的软金属 sheet 组成。在Java中,有没有办法手动设置扬声器的位置?我正在寻找这些方面的东西:

...
Speaker.setPosition(byte position);
// or
setSpeakerPosition(byte position);
...

提前致谢!

  1. 你错了。大多数扬声器不是金属板。 (如果你想了解典型扬声器的工作原理,试试这个:http://electronics.howstuffworks.com/speaker.htm

  2. 在 Java 中没有办法做到这一点(将 "plate" 移动到特定位置)。我怀疑它甚至可能在硬件级别......除非扬声器以一种相当奇怪的方式/昂贵/低效的方式实现。最重要的是,在 典型的 计算机音频系统中,您的程序和扬声器板之间有许多硬件和软件组件,其中 none就是这么用的。

实际上 java 中有一些类似这样的东西。你只需要明白声音本身没有。如果您只是将扬声器位置设置为一个值并保持不变,您最多只能听到一个短暂的脉冲,然后什么也听不到。

如果你想让它发出声音,它就必须移动。所以你不只是设置一个位置。你设置了一堆,随着时间的推移改变了价值。这是一个例子:

  /** Generates a tone.
  @param hz Base frequency (neglecting harmonic) of the tone in cycles per second
  @param msecs The number of milliseconds to play the tone.
  @param volume Volume, form 0 (mute) to 100 (max).
  @param addHarmonic Whether to add an harmonic, one octave up. */
  public static void generateTone(int hz,int msecs, int volume, boolean addHarmonic)
    throws LineUnavailableException {

    float frequency = 44100;
    byte[] buf;
    AudioFormat af;
    if (addHarmonic) {
      buf = new byte[2];
      af = new AudioFormat(frequency,8,2,true,false);
    } else {
      buf = new byte[1];
      af = new AudioFormat(frequency,8,1,true,false);
    }
    SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
    sdl = AudioSystem.getSourceDataLine(af);
    sdl.open(af);
    sdl.start();
    for(int i=0; i<msecs*frequency/1000; i++){
      double angle = i/(frequency/hz)*2.0*Math.PI;
      buf[0]=(byte)(Math.sin(angle)*volume);

      if(addHarmonic) {
        double angle2 = (i)/(frequency/hz)*2.0*Math.PI;
        buf[1]=(byte)(Math.sin(2*angle2)*volume*0.6);
        sdl.write(buf,0,2);
      } else {
        sdl.write(buf,0,1);
      }
    }
    sdl.drain();
    sdl.stop();
    sdl.close();
  }

来自 https://community.oracle.com/thread/1273219

这里用的SourceDataLine.write()和你想象中的Speaker.setPosition()没有太大区别。每次循环时,都会将一组字节(或谐波关闭时仅一个字节)写入 SourceDataLine。该字节的值为振幅。在这种情况下,它的范围从 -100 到 100。在理想的扬声器中,扬声器所处的位置将与该值成正比。在真实的扬声器中,它受物理扬声器频率响应的影响:

理想扬声器的频率响应应该是一条从 0Hz 到无穷大的水平线。如果您为狗或座头鲸播放音乐,这可能是个问题。对于大多数人来说,这已经足够接近我们能够听到的理想状态了。特别是如果您添加一点低音和高音以使其变平。不过,这意味着您准确控制扬声器位置的能力仅限于一定频率范围。

在上面的列表中,他们使用数学来构造一个非常简单的音频。特别是正弦波。听起来并不惊人。事实上,这听起来就像您在进行听力测试时听到的一样。但不管你信不信,你所听到的一切实际上都是许多像这样的简单声音加在一起的结果。这就是 http://en.wikipedia.org/wiki/Fourier_transform 教给我们的。

上面列表中的 generateTone() 方法将在傅里叶分析中称为 Frequency Domain. Here the audio signal is defined based on frequency(s). The math inside generateTone() is transforming that definition into the Time Domain。这里的音频信号是根据任一时间的位置定义的。 SourceDataLine.write() 请求将扬声器位置调整到特定位置。

因此,构建您的问题的一种方法是:什么 java 方法控制来自时域的音频? SourceDataLine.write() 只是众多以这种方式工作的方法之一。任何可以重现 sampled audio(用麦克风录制)的方法都适用于时域。在任何时候它都有一个扬声器位置的期望值。

其他音频 API,例如 MIDI,更多地在频域中运行。当您在钢琴上敲击特定的琴键时,您需要的是频率。有些细节使它变得复杂(谐波、起音、延音等),但这是基本的想法。如上所示,尝试从数学中构建有趣的声音是合成器所做的。

还有其他音频格式,其中一个字节不直接表示扬声器在特定时间的位置。有些做压缩。有些是有损的。但肯定有许多音频格式,其中一个字节确实直接表示扬声器位置。他们有一个采样率,就是测量位置的频率。

无论如何,这一切最终都必须转化为在特定时间将扬声器振膜置于特定位置。

扬声器板相对于其端子上施加的电压从其静止点移动。正电压使金属板远离线圈,负电压使它靠近线圈。您可以连接一个具有恒定直流电压的电池,金属板将移出并停留在那里(直到扬声器烧坏),因为扬声器在这一点上表现得像一个电阻器。正常的音频信号本质上是交流电。

计算机系统驱动扬声器的方式是将一系列时间序列的数值发送到称为 D/A 转换器的芯片,该转换器将每个特定数值转换为模拟电压。接下来,模拟电压通过放大器发送,最后发送到扬声器。有各种各样的 API 可用于创建数字信号并将它们路由到扬声器。

您可能认为您可以创建一个恒定值的数字信号作为将直流电应用到扬声器的一种方式。但它不会起作用,因为放大器的输出端有一个交流耦合滤波器,专门用于保护扬声器免受直流影响。它基本上是一个与扬声器串联的电容器。

您要实现的目标无法像您在 PC 中找到的音频放大器那样实现。

您可以将 SW 可编程直流电源连接到外部扬声器。