Алгоритм создания поддельного звукового визуализатора

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

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

Алгоритм с пояснением (и/или картинкой) подойдет. Псевдокод был бы очень кстати с вашей стороны. Фактический код 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;
}

person Ashkan Sarlak    schedule 16.05.2018    source источник
comment
Можете ли вы опубликовать свой код или хотя бы краткое описание того, что вы пробовали?   -  person see sharper    schedule 16.05.2018
comment
@seesharper хорошее замечание!   -  person Ashkan Sarlak    schedule 16.05.2018


Ответы (2)


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

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

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

person see sharper    schedule 16.05.2018
comment
Спасибо чувак. Я добился лучшего результата с упомянутыми вами обертонами и случайной амплитудой для каждого обертона. Я опубликую свой код и результат в следующем посте и приму ваш ответ за идею. - person Ashkan Sarlak; 16.05.2018

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

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

волна 1

волна 2

волна 3

person Ashkan Sarlak    schedule 16.05.2018