/******************************************************************************* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2013 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://www.catroid.org/catroid/licenseadditionalterm * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.catrobat.musicdroid.metronom; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.Log; import android.widget.ImageView; import org.catrobat.musicdroid.animation.MetronomAnimation; import org.catrobat.musicdroid.preferences.PreferenceManager; import org.catrobat.musicdroid.soundmixer.Statusbar; public class Metronom { private static final int METRONOM_OFF = 0; private static final int METRONOM_LIGHT = 1; private static final int METRONOM_LIGHT_AND_SOUND = 2; private static final int SAMPLE_RATE = 8000; private final int tickLengthInSamples = 1000; // private Context context = null; private ImageView metronomView = null; private AnimationDrawable animation = null; private boolean play = true; private double beatsPerMinute; private int beat; private int silenceDuration; private int metronomState; private double accentSound; private double sound; private AudioGenerator audioGenerator = new AudioGenerator(SAMPLE_RATE); public Metronom(Context context) { this.context = context; } private void initializeValues() { metronomView = Statusbar.getInstance().getMetronomLight(); beatsPerMinute = PreferenceManager.getInstance().getPreference(PreferenceManager.METRONOM_BPM_KEY); metronomState = PreferenceManager.getInstance().getPreference(PreferenceManager.METRONOM_VISUALIZATION_KEY); audioGenerator.createPlayer(); beat = 4; sound = 261.63; accentSound = 392.00; silenceDuration = (int) (((60 / beatsPerMinute) * SAMPLE_RATE) - tickLengthInSamples); animation = new MetronomAnimation(context, beatsPerMinute); } public void startMetronome() { Log.i("Metronom", "START"); initializeValues(); play = true; if (metronomState == METRONOM_OFF) { return; } if (metronomState >= METRONOM_LIGHT) { blink(); } if (metronomState == METRONOM_LIGHT_AND_SOUND) { play(); } } public void stopMetronome() { play = false; stopBlinking(); audioGenerator.destroyAudioTrack(); } private void play() { new Thread(new Runnable() { double[] tickArray = audioGenerator.getSineWave(tickLengthInSamples, SAMPLE_RATE, accentSound); double[] tockArray = audioGenerator.getSineWave(tickLengthInSamples, SAMPLE_RATE, sound); double silence = 0; double[] soundArray = new double[SAMPLE_RATE]; int tickSampleIndex = 0; int silenceSampleIndex = 0; int beatIndex = 0; @Override public void run() { while (play) { for (int i = 0; i < soundArray.length && play; i++) { if (tickSampleIndex < tickLengthInSamples) { if (beatIndex == 0) { soundArray[i] = tockArray[tickSampleIndex]; } else { soundArray[i] = tickArray[tickSampleIndex]; } tickSampleIndex++; } else { soundArray[i] = silence; silenceSampleIndex++; if (silenceSampleIndex >= silenceDuration) { tickSampleIndex = 0; silenceSampleIndex = 0; beatIndex++; if (beatIndex > (beat - 1)) { beatIndex = 0; } } } } audioGenerator.writeSound(soundArray); } } }).start(); } private void blink() { metronomView.setImageDrawable(animation); animation.start(); } private void stopBlinking() { animation.stop(); } }