Алгоритм создания поддельного аудио-визуализатора - PullRequest
0 голосов
/ 16 мая 2018

Кто-нибудь знает алгоритм для создания случайной серии чисел (например, 100 java-byte (> = - 127 & <= 127)), которые, когда они нарисованы в виде гистограммы, будут похожи на обычный звуковой спектр, как те SoundCloud? </p>

Я пытаюсь написать один, он имеет несколько расчетов Random и Sinus, но результат очень уродливый, это что-то среднее между синусоидальной волной и старой зубной щеткой. Я был бы очень благодарен, если бы вы направили меня к одному, который эстетически убедителен

Алгоритм с объяснением (и / или изображением) в порядке. Псевдокод был бы очень мил с вашей стороны. Фактический код JAVA является бонусом. : D

Edit:

Это код, который я сейчас использую. Это запутанно, но я в основном добавляю случайное отклонение к синусоидальной волне со случайной амплитудой (что я не уверен, если это была хорошая идея).

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;
}

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Основываясь на идее, которую дал мне Шарпер, этот код я сейчас использую:

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) х и т. Д. Или использовать другую серию частот.Я также рандомизирую амплитуду, чтобы каждый раз получать уникальную волну.

Вот некоторые волны, которые я рисую, используя этот код:

wave 1

wave 2

wave 3

0 голосов
/ 16 мая 2018

Реальная звуковая волна - это комбинация синусоидальных волн разных частот и амплитуд, сложенных вместе, а не случайных отклонений от синусоидальной волны. Сложная часть будет состоять в том, чтобы выбрать комбинацию амплитуд и частот волны, которая будет давать выход, который вам понравится субъективно! Однако большинство звуковых волн имеют базовую частоту, а затем несколько обертонов, которые «вписываются» в эту длину волны - например, он может иметь обертон на 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;
    }

Возможно, вы захотите изменить это, чтобы указать различные амплитуды, а также периоды для волн, которые вы комбинируете.

Комбинируя множество широко варьирующихся амплитуд и периодов (частот), вы должны методом проб и ошибок получить что-то убедительное.

...