Как получить звук Tick and Tock из синусоидальной волны и AudioTrack android? - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь разработать приложение для метронома. Из разных ресурсов я узнал, что SoundPool и MediaPlayer не подходят для метронома с высоким BPM, поэтому я сделал метроном, генерируя звуковую волну и используя AudioTrack.

AudioGenerator. Java class

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;

public class AudioGenerator {

    private int sampleRate;
    private AudioTrack audioTrack;

    public AudioGenerator(int sampleRate) {
        this.sampleRate = sampleRate;
    }

    public double[] getSineWave(int samples,int sampleRate,double frequencyOfTone){
        double[] sample = new double[samples];
        for (int i = 0; i < samples; i++) {
            sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/frequencyOfTone));
        }
                return sample;
    }

    public byte[] get16BitPcm(double[] samples) {
        byte[] generatedSound = new byte[2 * samples.length];
        int index = 0;
        for (double sample : samples) {
            // scale to maximum amplitude
            short maxSample = (short) ((sample * Short.MAX_VALUE));
            // in 16 bit wav PCM, first byte is the low order byte
            generatedSound[index++] = (byte) (maxSample & 0x00ff);
            generatedSound[index++] = (byte) ((maxSample & 0xff00) >>> 8);

        }
        return generatedSound;
    }

    public void createPlayer(){
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
                AudioFormat.ENCODING_PCM_16BIT, sampleRate,
                AudioTrack.MODE_STREAM);

        audioTrack.play();
    }

    public void writeSound(double[] samples) {
        byte[] generatedSnd = get16BitPcm(samples);
        audioTrack.write(generatedSnd, 0, generatedSnd.length);
    }

    public void destroyAudioTrack() {
        audioTrack.stop();
        audioTrack.release();
    }

}

Вот Метроном. java класс

package pntanasis.master_ex.android;

import android.util.Log;

public class Metronome {

        private double bpm =120;
        private int beat =4;
        private int noteValue;
        private int silence;

        private double beatSound = 900;
        private double sound = 1200;
        private final int tick = 1000; // samples of tick

        private boolean play = true;

        private AudioGenerator audioGenerator = new AudioGenerator(8000);

        public Metronome() {
                audioGenerator.createPlayer();
        }

        public void calcSilence() {
                silence = (int) (((60/bpm)*8000)-tick);
        }

        public void play() {
                calcSilence();
                double[] tick =
                        audioGenerator.getSineWave(this.tick, 8000, beatSound);
                double[] tock =
                        audioGenerator.getSineWave(this.tick, 8000, sound);
                double silence = 0;
                double[] sound = new double[8000];
                int t = 0,s = 0,b = 0;
                do {
                        for(int i=0;i<sound.length&&play;i++) {
                                if(t<this.tick) {
                                        if(b == 0)
                                                sound[i] = tock[t];
                                        else
                                                sound[i] = tick[t];
                                        t++;
                                } else {
                                        sound[i] = silence;
                                        s++;
                                        if(s >= this.silence) {
                                                t = 0;
                                                s = 0;
                                                b++;
                                                if(b > (this.beat-1))
                                                        b = 0;
                                        }
                                }
                        }
                        audioGenerator.writeSound(sound);
                } while(play);
        }

        public void stop() {
                play = false;
                audioGenerator.destroyAudioTrack();
        }

        /* Getters and Setters ... */
}

Метроном работает нормально, но всегда издает звуковой сигнал ( Я пробовал с другой частотой, частотой дискретизации, но всегда издает звуковой сигнал ). Мне нужен точный звук Tick and Tock. Я догадываюсь, что мне нужно изменить функцию getSineWave (). Может ли кто-нибудь помочь решить мою проблему?

Спасибо

...