code - download music app android
Tocando un tono arbitrario con Android (10)
Aquí hay otro blog que muestra un sintetizador simple más una interfaz de usuario
También podría estar interesado en csound o pdlib (lib de datos puros) para Android.
¿Hay alguna manera de hacer que Android emita un sonido de frecuencia arbitraria (es decir, no quiero tener archivos de sonido pregrabados)?
Miré a mi alrededor y ToneGenerator fue lo único que pude encontrar que estaba cerca, pero parece que solo es capaz de emitir los tonos DTMF estándar.
¿Algunas ideas?
Código modificado basado en la respuesta de Singhaks
public class MainActivity extends Activity {
private final int duration = 30; // seconds
private final int sampleRate = 8000;
private final int numSamples = duration * sampleRate;
private final double sample[] = new double[numSamples];
private final double freqOfTone = 440; // hz
private final byte generatedSnd[] = new byte[2 * numSamples];
Handler handler = new Handler();
private AudioTrack audioTrack;
private boolean play = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
8000, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, numSamples,
AudioTrack.MODE_STREAM);
}
@Override
protected void onResume() {
super.onResume();
// Use a new tread as this can take a while
Thread thread = new Thread(new Runnable() {
public void run() {
handler.post(new Runnable() {
public void run() {
playSound();
genTone();
}
});
}
});
thread.start();
}
void genTone(){
// fill out the array
while(play){
for (int i = 0; i < numSamples; ++i) {
// float angular_frequency =
sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
}
int idx = 0;
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
for (double dVal : sample) {
short val = (short) (dVal * 32767);
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
audioTrack.write(generatedSnd, 0, numSamples);
}
}
void playSound(){
play = true;
audioTrack.play();
}
}
Como hay un error en algunas versiones anteriores de Android que causa una pérdida de memoria al usar MODE_STATIC, modifiqué la respuesta de Xarph anterior para usar MODE_STREAM. Espero que ayude a algunos.
public void playTone(double freqOfTone, double duration) {
//double duration = 1000; // seconds
// double freqOfTone = 1000; // hz
int sampleRate = 8000; // a number
double dnumSamples = duration * sampleRate;
dnumSamples = Math.ceil(dnumSamples);
int numSamples = (int) dnumSamples;
double sample[] = new double[numSamples];
byte generatedSnd[] = new byte[2 * numSamples];
for (int i = 0; i < numSamples; ++i) { // Fill the sample array
sample[i] = Math.sin(freqOfTone * 2 * Math.PI * i / (sampleRate));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalized.
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
int i = 0 ;
int ramp = numSamples / 20 ; // Amplitude ramp as a percent of sample count
for (i = 0; i< ramp; ++i) { // Ramp amplitude up (to avoid clicks)
double dVal = sample[i];
// Ramp up to maximum
final short val = (short) ((dVal * 32767 * i/ramp));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = i; i< numSamples - ramp; ++i) { // Max amplitude for most of the samples
double dVal = sample[i];
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = i; i< numSamples; ++i) { // Ramp amplitude down
double dVal = sample[i];
// Ramp down to zero
final short val = (short) ((dVal * 32767 * (numSamples-i)/ramp ));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
AudioTrack audioTrack = null; // Get audio track
try {
int bufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize,
AudioTrack.MODE_STREAM);
audioTrack.play(); // Play the track
audioTrack.write(generatedSnd, 0, generatedSnd.length); // Load the track
}
catch (Exception e){
}
if (audioTrack != null) audioTrack.release(); // Track play done. Release track.
}
Envolví las maravillosas soluciones anteriores en un pequeño paquete ordenado que es más utilizable de fábrica como un simple zumbador configurable. Lo ejecuta en un hilo de fondo y tiene métodos de parada y reproducción y un puñado de opciones que puede configurar.
Está en JCenter para que pueda agregarlo a su lista de dependencias de esta manera
compile ''net.mabboud:android-tone-player:0.2''
y lo usa así para un zumbador continuo
ContinuousBuzzer tonePlayer = new ContinuousBuzzer();
tonePlayer.play();
// just an example don''t actually use Thread.sleep in your app
Thread.sleep(1000);
tonePlayer.stop();
o un timbre que se reproduce solo una vez y puede configurar la frecuencia y el volumen como este
OneTimeBuzzer buzzer = new OneTimeBuzzer();
buzzer.setDuration(5);
// volume values are from 0-100
buzzer.setVolume(50);
buzzer.setToneFreqInHz(110);
Publicación ampliada del blog aquí al respecto aquí GitHub aquí
Hay varios programas para esto, pero apestan. Medí algunos:
http://www.endolith.com/wordpress/2009/11/24/android-audio-applications/
Entonces no hagas lo que sea que ellos hagan. :RE
Mejorando el código anterior:
Añada aceleración de amplitud y reduzca la velocidad para evitar los clics.
Agregue código para determinar cuándo terminó la reproducción.
double duration = 1; // seconds
double freqOfTone = 1000; // hz
int sampleRate = 8000; // a number
double dnumSamples = duration * sampleRate;
dnumSamples = Math.ceil(dnumSamples);
int numSamples = (int) dnumSamples;
double sample[] = new double[numSamples];
byte generatedSnd[] = new byte[2 * numSamples];
for (int i = 0; i < numSamples; ++i) { // Fill the sample array
sample[i] = Math.sin(freqOfTone * 2 * Math.PI * i / (sampleRate));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalized.
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
int i = 0 ;
int ramp = numSamples / 20 ; // Amplitude ramp as a percent of sample count
for (i = 0; i< ramp; ++i) { // Ramp amplitude up (to avoid clicks)
double dVal = sample[i];
// Ramp up to maximum
final short val = (short) ((dVal * 32767 * i/ramp));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = i; i< numSamples - ramp; ++i) { // Max amplitude for most of the samples
double dVal = sample[i];
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
for (i = i; i< numSamples; ++i) { // Ramp amplitude down
double dVal = sample[i];
// Ramp down to zero
final short val = (short) ((dVal * 32767 * (numSamples-i)/ramp ));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
AudioTrack audioTrack = null; // Get audio track
try {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT, (int)numSamples*2,
AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length); // Load the track
audioTrack.play(); // Play the track
}
catch (Exception e){
RunTimeError("Error: " + e);
return false;
}
int x =0;
do{ // Montior playback to find when done
if (audioTrack != null)
x = audioTrack.getPlaybackHeadPosition();
else
x = numSamples;
}while (x<numSamples);
if (audioTrack != null) audioTrack.release(); // Track play done. Release track.
Originalmente encontré este código de ejemplo en un blog, pero tenía algunos errores que generaban algunos sonidos horrendos. Solucioné los errores y publiqué el código resultante aquí. ¡Parece que funciona bien para mí!
public class PlaySound extends Activity {
// originally from http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html
// and modified by Steve Pomeroy <[email protected]>
private final int duration = 3; // seconds
private final int sampleRate = 8000;
private final int numSamples = duration * sampleRate;
private final double sample[] = new double[numSamples];
private final double freqOfTone = 440; // hz
private final byte generatedSnd[] = new byte[2 * numSamples];
Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onResume() {
super.onResume();
// Use a new tread as this can take a while
final Thread thread = new Thread(new Runnable() {
public void run() {
genTone();
handler.post(new Runnable() {
public void run() {
playSound();
}
});
}
});
thread.start();
}
void genTone(){
// fill out the array
for (int i = 0; i < numSamples; ++i) {
sample[i] = Math.sin(2 * Math.PI * i / (sampleRate/freqOfTone));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
for (final double dVal : sample) {
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
}
void playSound(){
final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
}
}
vea esta útil biblioteca
https://github.com/karlotoy/perfectTune
es fácil de usar
agregar esto a sus dependencias
compile ''com.github.karlotoy:perfectTune:1.0.2''
Y lo usas así:
PerfectTune perfectTune = new PerfectTune();
perfectTune.setTuneFreq(desire_freq);
perfectTune.playTune();
para detener la melodía:
perfectTune.stopTune();
Do major (16 notas)
public class MainActivity extends AppCompatActivity {
private double mInterval = 0.125;
private int mSampleRate = 8000;
private byte[] generatedSnd;
private final double mStandardFreq = 440;
Handler handler = new Handler();
private AudioTrack audioTrack;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
// Use a new tread as this can take a while
final Thread thread = new Thread(new Runnable() {
public void run() {
byte[] tempByte = new byte[0];
for (int i = 0; i < 16 ; i++ ){
double note = getNoteFrequencies(i);
byte[] tonByteNote = getTone(mInterval, mSampleRate, note);
tempByte = concat(tonByteNote, tempByte);
}
generatedSnd = tempByte;
handler.post(new Runnable() {
public void run() {
playTrack(generatedSnd);
}
});
}
});
thread.start();
}
public byte[] concat(byte[] a, byte[] b) {
int aLen = a.length;
int bLen = b.length;
byte[] c= new byte[aLen+bLen];
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
private double getNoteFrequencies(int index){
return mStandardFreq * Math.pow(2, (double) index/12.0d);
}
private byte[] getTone(double duration, int rate, double frequencies){
int maxLength = (int)(duration * rate);
byte generatedTone[] = new byte[2 * maxLength];
double[] sample = new double[maxLength];
int idx = 0;
for (int x = 0; x < maxLength; x++){
sample[x] = sine(x, frequencies / rate);
}
for (final double dVal : sample) {
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedTone[idx++] = (byte) (val & 0x00ff);
generatedTone[idx++] = (byte) ((val & 0xff00) >>> 8);
}
return generatedTone;
}
private AudioTrack getAudioTrack(int length){
if (audioTrack == null)
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
mSampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, length,
AudioTrack.MODE_STATIC);
return audioTrack;
}
private double sine(int x, double frequencies){
return Math.sin( 2*Math.PI * x * frequencies);
}
void playTrack(byte[] generatedSnd){
getAudioTrack(generatedSnd.length)
.write(generatedSnd, 0, generatedSnd.length);
audioTrack.play();
}
}
float synth_frequency = 440;
int minSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minSize,
AudioTrack.MODE_STREAM);
audioTrack.play();
short[] buffer = new short[minSize];
float angle = 0;
while (true)
{
if (play)
{
for (int i = 0; i < buffer.length; i++)
{
float angular_frequency =
(float)(2*Math.PI) * synth_frequency / SAMPLE_RATE;
buffer[i] = (short)(Short.MAX_VALUE * ((float) Math.sin(angle)));
angle += angular_frequency;
}
audioTrack.write(buffer, 0, buffer.length);
}
// Puedes agregar un valor arbitrario en synth_frequency para obtener un cambio de sonido; por ejemplo, puedes agregar una variable aleatoria para obtener sonido