一种生成假音频可视化器的算法
An Algorithm for producing fake audio visualizer
有没有人知道一种算法来制作随机数字序列(比如 100 java-byte (>=-127 & <= 127) ),当绘制成条形图时,会是相似的到常规音频频谱,比如那些 SoundCloud 的频谱?
我正在尝试写一个,它有多个随机和正弦计算,但结果非常难看,它介于正弦波和旧牙刷之间。如果您的代码指导我找到一个在美学上令人信服的代码,我将不胜感激
有解释的算法(and/or图片)就可以了。伪代码对你很好。实际的 JAVA 代码是奖励。 :D
编辑:
这是我现在使用的代码。这很复杂,但我基本上是在具有随机幅度的正弦波中添加随机偏差(我不确定这是否是个好主意)。
private static final int FREQ = 7;
private static final double DEG_TO_RAD = Math.PI / 180;
private static final int MAX_AMPLITUDE = 127;
private static final float DEVIATION = 0.1f; // 10 percent is maximum deviation
private void makeSinusoidRandomBytes() {
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
int amplitude = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE/2;
byte dev = (byte) (random.nextInt((int) Math.max(Math.abs(2 * DEVIATION * amplitude), 1))
- Math.abs(DEVIATION * amplitude));
bytes[i] = (byte) (Math.sin(i * FREQ * DEG_TO_RAD) * amplitude - dev);
}
this.bytes = bytes;
}
真正的声波实际上是不同频率和幅度的正弦波叠加在一起的组合,而不是正弦波的随机偏差。困难的部分是选择波幅和频率的组合,以产生您主观上喜欢的输出!然而,大多数声波都有一个基频,然后是 "fit into" 该波长的泛音 - 例如,它可能在基频的 3/2 * 和振幅为基频的 2/3 处具有泛音。通过组合这些泛音并将生成的波形缩放到 -127 - +127 范围,您将获得实际的声波。
以下代码是 C# 代码,但与 Java 足够接近,可以让您了解一下。它来自一个游戏,我需要将许多正弦波组合在一起以创建各种类型的振荡效果:
/// <summary>
/// Return a value between 0 and 1 based on a sine-wave oscillating with a given combination of periods at a given point in time
/// </summary>
/// <param name="time">time to get wave value at</param>
/// <param name="periods">lengths of waves</param>
/// <returns>height of wave</returns>
public static float MultiPulse(float time, params float[] periods)
{
float c = 0;
foreach (float p in periods)
{
float cp = (MathHelper.Pi / p) * time;
float s = ((float)Math.Sin(cp) + 1) / 2;
c += s / periods.Length;
}
return c;
}
您可能想要修改它以允许您指定不同的振幅以及要组合的波的周期。
通过组合许多变化很大的幅度和周期(频率),您应该通过反复试验能够得到令人信服的东西。
基于 see sharper 给我的想法,这是我现在使用的代码:
int mainAmp = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE / 2;
int overtoneAmp = random.nextInt(MAX_AMPLITUDE * 2 / 3) - MAX_AMPLITUDE / 3;
int overtone2Amp = random.nextInt(MAX_AMPLITUDE * 4 / 7) - MAX_AMPLITUDE / 2 * 7;
int mainFreq = random.nextInt(7) + 7;
int overtoneFreq = mainFreq * 3 / 2;
int overtone2Freq = mainFreq * 7 / 4;
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
bytes[i] = (byte) (Math.sin(i * mainFreq * DEG_TO_RAD) * mainAmp
+ Math.sin(i * overtoneFreq * DEG_TO_RAD) * overtoneAmp
+ Math.sin(i * overtone2Freq * DEG_TO_RAD) * overtone2Amp);
}
我的应用的主频率在 8 到 15 之间。你可以玩那些。我使用的另外两个泛音是主频率的 (2 - 1/2)x 和 (2 - 1/4)x。您可以添加更多(2 - 1/8)x 等。或使用另一系列的频率。我还随机化振幅,每次都获得一个独特的波。
这些是我使用此代码绘制的一些波浪:
有没有人知道一种算法来制作随机数字序列(比如 100 java-byte (>=-127 & <= 127) ),当绘制成条形图时,会是相似的到常规音频频谱,比如那些 SoundCloud 的频谱?
我正在尝试写一个,它有多个随机和正弦计算,但结果非常难看,它介于正弦波和旧牙刷之间。如果您的代码指导我找到一个在美学上令人信服的代码,我将不胜感激
有解释的算法(and/or图片)就可以了。伪代码对你很好。实际的 JAVA 代码是奖励。 :D
编辑:
这是我现在使用的代码。这很复杂,但我基本上是在具有随机幅度的正弦波中添加随机偏差(我不确定这是否是个好主意)。
private static final int FREQ = 7;
private static final double DEG_TO_RAD = Math.PI / 180;
private static final int MAX_AMPLITUDE = 127;
private static final float DEVIATION = 0.1f; // 10 percent is maximum deviation
private void makeSinusoidRandomBytes() {
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
int amplitude = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE/2;
byte dev = (byte) (random.nextInt((int) Math.max(Math.abs(2 * DEVIATION * amplitude), 1))
- Math.abs(DEVIATION * amplitude));
bytes[i] = (byte) (Math.sin(i * FREQ * DEG_TO_RAD) * amplitude - dev);
}
this.bytes = bytes;
}
真正的声波实际上是不同频率和幅度的正弦波叠加在一起的组合,而不是正弦波的随机偏差。困难的部分是选择波幅和频率的组合,以产生您主观上喜欢的输出!然而,大多数声波都有一个基频,然后是 "fit into" 该波长的泛音 - 例如,它可能在基频的 3/2 * 和振幅为基频的 2/3 处具有泛音。通过组合这些泛音并将生成的波形缩放到 -127 - +127 范围,您将获得实际的声波。
以下代码是 C# 代码,但与 Java 足够接近,可以让您了解一下。它来自一个游戏,我需要将许多正弦波组合在一起以创建各种类型的振荡效果:
/// <summary>
/// Return a value between 0 and 1 based on a sine-wave oscillating with a given combination of periods at a given point in time
/// </summary>
/// <param name="time">time to get wave value at</param>
/// <param name="periods">lengths of waves</param>
/// <returns>height of wave</returns>
public static float MultiPulse(float time, params float[] periods)
{
float c = 0;
foreach (float p in periods)
{
float cp = (MathHelper.Pi / p) * time;
float s = ((float)Math.Sin(cp) + 1) / 2;
c += s / periods.Length;
}
return c;
}
您可能想要修改它以允许您指定不同的振幅以及要组合的波的周期。
通过组合许多变化很大的幅度和周期(频率),您应该通过反复试验能够得到令人信服的东西。
基于 see sharper 给我的想法,这是我现在使用的代码:
int mainAmp = random.nextInt(MAX_AMPLITUDE) - MAX_AMPLITUDE / 2;
int overtoneAmp = random.nextInt(MAX_AMPLITUDE * 2 / 3) - MAX_AMPLITUDE / 3;
int overtone2Amp = random.nextInt(MAX_AMPLITUDE * 4 / 7) - MAX_AMPLITUDE / 2 * 7;
int mainFreq = random.nextInt(7) + 7;
int overtoneFreq = mainFreq * 3 / 2;
int overtone2Freq = mainFreq * 7 / 4;
byte[] bytes = new byte[AUDIO_VISUALIZER_DENSITY];
for (int i = 0; i < AUDIO_VISUALIZER_DENSITY; i++) {
bytes[i] = (byte) (Math.sin(i * mainFreq * DEG_TO_RAD) * mainAmp
+ Math.sin(i * overtoneFreq * DEG_TO_RAD) * overtoneAmp
+ Math.sin(i * overtone2Freq * DEG_TO_RAD) * overtone2Amp);
}
我的应用的主频率在 8 到 15 之间。你可以玩那些。我使用的另外两个泛音是主频率的 (2 - 1/2)x 和 (2 - 1/4)x。您可以添加更多(2 - 1/8)x 等。或使用另一系列的频率。我还随机化振幅,每次都获得一个独特的波。
这些是我使用此代码绘制的一些波浪: