0

我正在尝试制作自己的回声垫,实际上直到回声部分都可以

起初我从声音创作开始,它很棒,但是当我开始添加回声效果时,它听起来很愚蠢。

编码

package com.echo;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

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

public class WavePlay {

    private final static float duration = 1f; // seconds
    private final static int sampleRate = 44100;
    private final static int numSamples = (int) (duration * sampleRate);
    private final static double sample[] = new double[numSamples];

    private static SourceDataLine line = null;
    private static int freqOfTone = 30;

    private static byte[] original;

    public static void main(String[] args) {

        AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                sampleRate, 8, 1, 1, sampleRate, true);

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(format);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < numSamples; ++i) {
            sample[i] = 255 * Math.sin(2 * Math.PI * i
                    / (sampleRate / freqOfTone));

        }

        final byte generatedSnd[] = new byte[100000];

        original = new byte[generatedSnd.length];

        for (int i = 0; i < 20000; i++) {

            generatedSnd[i] = (byte) (sample[i % sample.length] + 1);

            original[i] = generatedSnd[i];

        }

        // Echo

        int delaySamples = 10000;

        float decay = 0.3f;

        for (int j = 0; j < 5; j++) {
            for (int i = 0; i < generatedSnd.length; i++) {

                if (i < delaySamples * (j + 1)) {
                    continue;
                }

                generatedSnd[i] += (byte) (original[i - delaySamples * (j + 1)] * decay);

            }

            decay *= 0.4;
        }

        // play

        InputStream source = new ByteArrayInputStream(generatedSnd);

        int numRead = 0;
        byte[] buf = new byte[line.getBufferSize()];

        line.start();
        // read and play chunks of the audio
        try {
            while ((numRead = source.read(buf, 0, buf.length)) >= 0) {
                int offset = 0;
                while (offset < numRead)
                    offset += line.write(buf, offset, numRead - offset);
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        line.drain();
        line.stop();
        line.close();

        System.exit(0);
    }

}

请运行代码并告诉我是否有任何问题

非常感谢提前

4

1 回答 1

0

事实是有几个错误,下面的代码通过这些更改产生了更清晰的结果:

  • 写入缓冲区中的值必须小于 Byte.MAX_VALUE(如果在支持短数组的 android 上写入,您的偏移量将为 SHORT.MAX_VALUE)

  • 示例创建以更清洁的方式实现

编码

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

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

public class WavePlay {

    public static void main(String[] args) {

        float duration = 1f; // seconds
        int sampleRate = 44100;
        int numSamples = (int) (duration * sampleRate);
        double sample[] = new double[numSamples];

        SourceDataLine line = null;
        int freqOfTone = 300;

        double[] original;

        AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                sampleRate, 8, 1, 1, sampleRate, true);

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(format);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }

        double increment = 2 * Math.PI * freqOfTone / sampleRate;
        double angle = 0;

        for (int i = 0; i < numSamples; ++i) {
            sample[i] = (Math.sin(angle)) * Byte.MAX_VALUE;
            angle += increment;
        }

        final double generatedSnd[] = new double[200000];

        original = new double[generatedSnd.length];

        for (int i = 0; i < 20000; i++) {
            generatedSnd[i] = sample[i % sample.length];

            original[i] = generatedSnd[i];

        }

        // Echo

        int delaySamples = 20000;

        float decay = 0.8f;

        double maxValue = Byte.MAX_VALUE;

        for (int j = 0; j < 10; j++) {
            for (int i = 0; i < generatedSnd.length; i++) {

                if (i < delaySamples * (j + 1)) {
                    continue;
                }

                generatedSnd[i] += original[i - delaySamples * (j + 1)] * decay;
                if(generatedSnd[i] > maxValue){
                    maxValue = generatedSnd[i]; 
                }

            }

            decay *= 0.5;
        }

        //scale to fit byte length (8 bit)
        byte[] out = new byte[generatedSnd.length];

        for (int i = 0; i < out.length; i++) {
            out[i] = (byte)(Byte.MAX_VALUE * generatedSnd[i] / maxValue);
        }

        // play

        InputStream source = new ByteArrayInputStream(out);

        int numRead = 0;
        byte[] buf = new byte[line.getBufferSize()];

        line.start();
        // read and play chunks of the audio
        try {
            while ((numRead = source.read(buf, 0, buf.length)) >= 0) {
                int offset = 0;
                while (offset < numRead)
                    offset += line.write(buf, offset, numRead - offset);
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        line.drain();
        line.stop();
        line.close();

        System.exit(0);
    }

}
于 2012-10-02T07:49:45.927 回答