gpt4 book ai didi

java - 使用Java单独控制声道的增益

转载 作者:行者123 更新时间:2023-12-01 10:00:17 24 4
gpt4 key购买 nike

我写了这个小信号生成方法。我的目标是在两个 channel (左和右)之间产生轻微的时间延迟或 channel 之间的增益略有差异时产生蜂鸣声。目前,我通过用一个 channel 的零和第二个 channel 的值填充缓冲区来创建延迟,并进一步向下交换 channel 之间的行为(如果您有任何提示或想法如何更好地做到这一点,我们将不胜感激。)下一阶段正在做类似的增益事情。我已经看到 Java 通过 FloatControl 提供内置增益控制:

FloatControl gainControl = 
(FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);

但我不知道如何分别控制每个 channel 的增益。有内置的方法可以做到这一点吗?我是否需要两个独立的流,每个 channel 一个?如果是这样我如何同时播放它们?我对声音编程相当陌生,如果有更好的方法,请告诉我。很感谢任何形式的帮助。

这是我到目前为止的代码:

    public static void generateTone(int delayR, int delayL, double gainRightDB, double gainLeftDB)
throws LineUnavailableException, IOException {

// in hz, number of samples in one second
int sampleRate = 100000; // let sample rate and frequency be the same

// how much to add to each side:
double gainLeft = 100;//Math.pow(10.0, gainLeftDB / 20.0);
double gainRight = 100;// Math.pow(10.0, gainRightDB / 20.0);;

// click duration = 40 us
double duration = 0.08;
double durationInSamples = Math.ceil(duration * sampleRate);

// single delay window duration = 225 us
double baseDelay = 0.000225;
double samplesPerDelay = Math.ceil(baseDelay * sampleRate);

AudioFormat af;

byte buf[] = new byte[sampleRate * 4]; // one second of audio in total
af = new AudioFormat(sampleRate, 16, 2, true, true); // 44100 Hz, 16 bit, 2 channels


SourceDataLine sdl = AudioSystem.getSourceDataLine(af);

sdl.open(af);

sdl.start();

// only one should be delayed at a time
int delayRight = delayR;
int delayLeft = delayL;

int freq = 1000;

/*
* NOTE:
* The buffer holds data in groups of 4. Every 4 bytes represent a single sample. The first 2 bytes
* are for the left side, the other two are for the right. We take 2 each time because of a 16 bit rate.
*
*
*/
for(int i = 0; i < sampleRate * 4; i++){
double time = ((double)i/((double)sampleRate));

// Left side:
if (i >= delayLeft * samplesPerDelay * 4 // when the left side plays
&& i % 4 < 2 // access first two bytes in sample
&& i <= (delayLeft * 4 * samplesPerDelay)
+ (4 * durationInSamples)) // make sure to stop after your delay window

buf[i] = (byte) ((1+gainLeft) * Math.sin(2*Math.PI*(freq)*time)); // sound in left ear
//Right side:
else if (i >= delayRight * samplesPerDelay * 4 // time for right side
&& i % 4 >= 2 // use second 2 bytes
&& i <= (delayRight * 4 * samplesPerDelay)
+ (4 * durationInSamples)) // stop after your delay window


buf[i] = (byte) ((1+gainRight) * Math.sin(2*Math.PI*(freq)*time)); // sound in right ear

}

for (byte b : buf)
System.out.print(b + " ");
System.out.println();

sdl.write(buf,0,buf.length);
sdl.drain();
sdl.stop();


sdl.close();
}

最佳答案

您希望发出嘟嘟声的距离有多远?我编写了一个程序,使正弦蜂鸣声的间隔高达几百帧(44100 fps),并用源代码 here 发布了它。欢迎您检查/复制/重写。

在如此低的分离度下,声音在感知上仍然保持融合,但可能开始移动到一只耳朵或另一只耳朵。我写这篇文章是因为我想将音量平移与基于延迟的平移进行比较。为了能够灵活地测试多个文件,代码比您开始使用的代码稍微更加模块化。不过,我不会声称我写的东西更好。

一个类采用单声道 PCM(范围为 float ,-1 到 1)数组,并将其转换为立体声数组,并在 channel 之间具有所需的帧延迟。同一类还可以将单声道文件拆分为立体声文件,其中唯一的区别是音量,并且有第三个选项,当您将单声道数据转换为立体声时,您可以使用延迟和音量差异的组合。

单文件:F1、F2、F3,...立体声 F1L、F1R、F2L、F2R、F3L、F3R、...

但是如果添加延迟,例如向右 2 帧:

立体声文件 F1L、0、F2L、0、F3L、F1R、F4L、F2R、...

其中 F 是表示音频波的归一化 float (介于 -1 和 1 之间)。

制作蜂鸣声的第一个单声道数组只需像您一样使用正弦函数即可。您可以通过在某些帧的过程中逐渐增大音量来“圆化边缘”,以最大程度地减少突然开始或停止的不连续性所产生的咔嗒声。

编写了另一个类,其唯一目的是通过 SourceDataLine 输出立体 float 组。通过将音频输出乘以 0 到 1 之间的系数来处理音量。标准化值乘以 32767 将其转换为带符号的 Shorts,并将 Shorts 分解为我使用的格式的字节(16 位、44100 fps、立体声、小端)。

拥有一个数组播放音频类是很巧妙的。它的数组很像 Clips,但您可以直接访问数据。通过此类,您可以构建和重用许多声音数组。我想我还包含一些代码,可以将 wav 文件加载到这个 DIY 剪辑中。

this thread at Java-Gaming.org上有关于此代码的更多讨论.

我最终使用了在这里学到的一些知识来制作一个简化的实时 3D 声音系统。不过,设置此类内容的“最佳”方法取决于您的目标。例如,对于我的 3D,我编写了一个延迟工具,允许从左右立体声单独读取,并且音频混合器和播放比简单的数组到 SourceDataLine 播放器更复杂。

关于java - 使用Java单独控制声道的增益,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36863481/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com