gpt4 book ai didi

java - 在 Java 中生成音调并改变它的音色?

转载 作者:行者123 更新时间:2023-12-04 01:48:17 26 4
gpt4 key购买 nike

我想制作一个 Java 程序,可以生成一个音符,并在播放时改变它的音色和音高。

我想用数字来改变音色,这样我就可以从一种音色平滑地过渡到另一种音色,音高也是如此。

我的目标是像这样运行一些代码

for(int i = 0; i < 20; i++ ) {
toneGenerator.changeTimber( toneGenerator.timbre + 10.0 );
toneGenerator.changePitch ( toneGenerator.pitch + 10.0 );
}

目前我不了解声音在 PC 上是如何构成的,所以我真的只是想问问是否有人知道让我学习如何做这两件事的最短路径。

我希望数学会很简单,但看起来不太可能。

最佳答案

这是一个用 Java 编写的音调合成器,具有多种功能。

  • 音高控制(每秒循环数)
  • 振幅控制(以数字步进)
  • 用于指示振幅何时过高(这会导致音频剪辑导致音调失真)的最小和最大统计数据
  • 控制音调持续时间(以秒为单位)
  • 控制任意数量的谐波的相对振幅(这决定了音质或波形,这是产生音符音色的几个因素之一)

在持续时间内实时修改主谐波和其他谐波的振幅不是 SimpleSynth 类的功能之一。物理乐器的音符具有该功能。 SimpleSynth 类不播放音符序列,但可以对其进行修改以相对轻松地播放。

主要是,它很好地演示了音频合成原理、谐波以及使用 Java 在运行时通过默认音频输出播放数字音频样本序列。也没有对谐波进行相移的工具,但这是一个有点无关紧要的缺点,因为谐波的相位特性不是人耳能够检测到的。

数学在 playSound() 方法的注释部分进行了解释。如果你上过最基本的三角学课,你就有理解这个程序的数学理论。阅读一些有关数字音频、信号采样以及如何在吉他等弦乐器上弹拨泛音的内容也可能有助于理解。

标准数字音频术语用于常量和变量命名。如果希望在音符过程中修改音高和音色,产生这种效果的数学运算并不简单,但一旦学会了下面的数学运算,就会存在理解基础,并且可以逐步添加进一步的合成功能。

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.SourceDataLine;

class SimpleSynth
{
private static int SAMPLE_BITS = 16;
private static int CHANNELS = 1;
private static boolean SIGNED_TRUE = true;
private static boolean BIG_ENDIAN_FALSE = false;
private static float CDROM_SAMPLE_FREQ = 44100;

private SourceDataLine line;

private double dDuration;
private double dCyclesPerSec;
private double dAmplitude;
private double[] adHarmonics;

private double dMin;
private double dMax;

public SimpleSynth(String[] asArguments) throws Exception
{
dDuration = Double.parseDouble(asArguments[0]);
dCyclesPerSec = Double.parseDouble(asArguments[1]);
dAmplitude = Double.parseDouble(asArguments[2]);
adHarmonics = new double[asArguments.length - 3];
for (int i = 0; i < adHarmonics.length; ++ i)
adHarmonics[i] = Double.parseDouble(
asArguments[i + 3]);

AudioFormat format = new AudioFormat(
CDROM_SAMPLE_FREQ, SAMPLE_BITS,
CHANNELS, SIGNED_TRUE, BIG_ENDIAN_FALSE);
line = AudioSystem.getSourceDataLine(format);
line.open();
line.start();
}

public void closeLine()
{
line.drain();
line.stop();
}

public void playSound()
{
// allocate and prepare byte buffer and its index
int iBytes = (int) (2.0 * (0.5 + dDuration)
* CDROM_SAMPLE_FREQ);
byte[] ab = new byte[iBytes];
int i = 0;

// iterate through sample radian values
// for the specified duration
short i16;
double dSample;
double dRadiansPerSample = 2.0 * Math.PI
* dCyclesPerSec / CDROM_SAMPLE_FREQ;
double dDurationInRadians = 2.0 * Math.PI
* dCyclesPerSec * dDuration;
dMin = 0.0;
dMax = 0.0;
for (double d = 0.0;
d < dDurationInRadians;
d += dRadiansPerSample)
{
// add principle and the dot product of harmonics
// and their amplitudes relative to the principle
dSample = Math.sin(d);
for (int h = 0; h < adHarmonics.length; ++ h)
dSample += adHarmonics[h]
* Math.sin((h + 2) * d);

// factor in amplitude
dSample *= dAmplitude;

// adjust statistics
if (dMin > dSample)
dMin = dSample;
if (dMax < dSample)
dMax = dSample;

// store in byte buffer
i16 = (short) (dSample);
ab[i ++] = (byte) (i16);
ab[i ++] = (byte) (i16 >> 8);
}

// send the byte array to the audio line
line.write(ab, 0, i);
}

public void printStats()
{
System.out.println("sample range was ["
+ dMin + ", " + dMax + "]"
+ " in range of [-32768, 32767]");

if (dMin < -32768.0 || dMax > 32767.0)
System.out.println("sound is clipping"
+ "(exceeding its range),"
+ " so use a lower amplitude");
}

public static void main(String[] asArguments)
throws Exception
{
if (asArguments.length < 3)
{
System.err.println("usage: java SimpleSynth"
+ " <duration>"
+ " <tone.cycles.per.sec>"
+ " <amplitude>"
+ " [<relative.amplitude.harmonic.2>"
+ " [...]]");
System.err.println("pure tone:"
+ " java SimpleSynth 1 440 32767");
System.err.println("oboe-like:"
+ " java SimpleSynth 1 440 15000 0 1 0 .9");
System.err.println("complex:"
+ " java SimpleSynth 1 440 800 .3"
+ " .5 .4 .2 .9 .7 5 .1 .9 12 0 3"
+ " .1 5.2 2.5 .5 1 7 6");

System.exit(0);
}

SimpleSynth synth = new SimpleSynth(asArguments);
synth.playSound();
synth.closeLine();
synth.printStats();

System.exit(0);
}
}

关于java - 在 Java 中生成音调并改变它的音色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24888902/

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