Почему этот программно сгенерированный музыкальный аккорд не звучит правильно?

У меня есть следующий класс, который генерирует буфер, содержащий звуковые данные:

package musicbox.example;

import javax.sound.sampled.LineUnavailableException;

import musicbox.engine.SoundPlayer;

public class CChordTest {

    private static final int SAMPLE_RATE = 1024 * 64;
    private static final double PI2 = 2 * Math.PI;

    /*
     * Note frequencies in Hz.
     */
    private static final double C4 = 261.626;
    private static final double E4 = 329.628;
    private static final double G4 = 391.995;

    /**
     * Returns buffer containing audio information representing the C chord
     * played for the specified duration.
     * 
     * @param duration The duration in milliseconds.
     * @return Array of bytes representing the audio information.
     */
    private static byte[] generateSoundBuffer(int duration) {

        double durationInSeconds = duration / 1000.0;
        int samples = (int) durationInSeconds * SAMPLE_RATE;

        byte[] out = new byte[samples];

        for (int i = 0; i < samples; i++) {
            double value = 0.0;
            double t = (i * durationInSeconds) / samples;
            value += Math.sin(t * C4 * PI2); // C note
            value += Math.sin(t * E4 * PI2); // E note
            value += Math.sin(t * G4 * PI2); // G note
            out[i] = (byte) (value * Byte.MAX_VALUE);
        }

        return out;
    }

    public static void main(String... args) throws LineUnavailableException {
        SoundPlayer player = new SoundPlayer(SAMPLE_RATE);
        player.play(generateSoundBuffer(1000));
    }

}

Возможно, я неправильно понимаю некоторую физику или математику здесь, но кажется, что каждая синусоида должна представлять звук каждой ноты (C, E и G), и, суммируя три синусоиды, я должен услышать нечто похожее на то, когда я играю эти три ноты одновременно на клавиатуре. То, что я слышу, однако, даже близко не к этому.

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

Может кто-нибудь заметит, что я делаю не так?

1 ответ

Решение

Для объединения аудиосигналов необходимо усреднить их выборки, а не суммировать их.

Разделите значение на 3 перед преобразованием в байт.

Вы не говорите, каким образом это звучит неправильно, добавляя три значения sin, например, вы получите сигнал в диапазоне от -3.0 до 3.0 и, следовательно, обрежете его, когда примените свой *Byte.MAX_VALUE, поэтому усреднение, вероятно, сработало для вас, добавление является правильным, просто вам нужно масштабировать результат после того, как для предотвращения отсечения и деления на количество синусоидальных волн это самый простой способ сделать это. Но если вы начнете динамически изменять число синусоидальных волн и попытаетесь использовать ту же стратегию, что и не получите ожидаемого результата, вам придется масштабировать сигнал, когда сигнал самый громкий. Помните, что реальный звук не будет иметь максимальную амплитуду, поэтому вам не нужно беспокоиться об этом вдвоем, если вы не синтезируете звук, а то, как мы воспринимаем громкость звука, является логарифмическим, поэтому сигнал с половиной амплитуды - это разница -3 дБ, что довольно близко к минимальному изменению амплитуды, которое мы можем услышать.

Другие вопросы по тегам