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