Gracias de antemano.
No llego a tender si lo que quieres es limitarte a copiar los sonidos
de la banda de 1Khz o por el contrario tomar muestras con frecuencia
de 1Khz pero con la gama completa, pero no creo que un Android normal
tenga bastante potencia para procesar el audio con soltura (y eliminar
por ejemplo todos los sonidos que excedan el Khz), quizás para eso lo
mejor sea filtrarlo a posteriori desde el PC o el propio Android.
Suerte con tu aplicación medica.
Tal vez no me he expllicado bien, en realidad la frecuencia es lo de
menos, yo necesito tener un ficherio binario donde estén las muestras
capturadas de AUDIO, pero no las quiero codificadas, yo quiero la
señal digital, previa a codificarse, por tanto, me gustaría tener un
archivo .wav, o algo parecido, donde puedan estar las muestras de
audio sin codificarlas.
En el diseño que yo he realizado, lo único que consigo es o bien tener
un archivo .3gp o bien, un archivo en el que su formato es AMR.
No se bien bien como hacerlo, ya que me es importantisimo conseguir
esas muestras y no codificadas, ya que sería un trabajo inútil y
costoso tenerlas que decodificar.
Si se te ocurre alguna posible solució o opción a tratar, te estaré
enormemente agradecido.
Gracias de antemano.
Y lo peor es que revisando la documentación, no existe una forma desde
el SDK de capturar WAV o PCM desde las fuentes de audio de Android.
Solo quedaría preparar código nativo para tu Android y poder crear
dicha funcionalidad...
A mi eso ya se me escapa demasiado
Al fín he conseguido capturar la señal AUDIO y almacenarla en .PCM
(los datos audio son totalmente en bruto, que es lo que necesitaba)
Ahora me ha surgido otro problema...
Resulta que en mi diseño utilizo 3 botones, uno para GRABAR, el otro
para PARAR y el otro para SALIR, el caso es que los botones de parar y
de salir cuando no he pulsado el de grabar funcionan correctamente, el
hecho es, que cuando pulso el de grabar inhabilita la pulsación de
cualquier otro botón y eso me obliga a tener que fianlizar la
grabación "matando" la aplicación.
Te adjunto el código, por si quieres echarle un ojo, (por si te
interesa la captura de AUDIO en bruto) y por si me puede ayudar:
Gracias de antemano.
( Creo que el problema está en un while(isReading) pero ya lo verás tu
mismo . . .)
Te adjunto también el main.xml, y strings.xml
y recuerda que debes añadir el permiso audiorecord al android
manifest.
----------------------------------------------------------------------------------------------------
package com.desarrolladores.android.reproductor.musica;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ReproductorMusica extends Activity implements
OnClickListener, Runnable {
private TextView estado;
private TextView estado2;
private ProgressBar progreso;
private Button reproducir;
private Button detener;
private MediaPlayer mp;
private Button grabar;
private Button parar;
private Button salir;
boolean isRecording=false;
int frequency = 8000;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
AudioRecord audioRecord = new
AudioRecord(MediaRecorder.AudioSource.MIC,
frequency,
channelConfiguration,
audioEncoding,
bufferSize);
short[] buffer = new short[bufferSize];
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Obtenermos una referencia a todos los elementos
estado = (TextView) findViewById(R.id.estado);
estado2 = (TextView) findViewById(R.id.estado2);
progreso = (ProgressBar) findViewById(R.id.progreso);
reproducir = (Button) findViewById(R.id.reproducir);
detener = (Button) findViewById(R.id.detener);
grabar = (Button) findViewById(R.id.grabar);
salir = (Button) findViewById(R.id.salir);
parar = (Button) findViewById(R.id.parar);
reproducir.setOnClickListener(this);
detener.setOnClickListener(this);
grabar.setOnClickListener(this);
parar.setOnClickListener(this);
salir.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.equals(reproducir)){
// Detenemos si est�bamos reproduciendo
if(mp != null && mp.isPlaying()) return;
mp = MediaPlayer.create(ReproductorMusica.this, R.raw.musica);
mp.start();
estado.setText(R.string.reproduciendo);
progreso.setVisibility(ProgressBar.VISIBLE);
progreso.setProgress(0);
progreso.setMax(mp.getDuration());
new Thread(this).start();
}
if(v.equals(detener) && mp!=null){
mp.stop();
mp = null;
estado.setText(R.string.detenido);
progreso.setVisibility(ProgressBar.GONE);
}
if(v.equals(grabar)){
estado2.setText(R.string.grabando);
record();
}
if(v.equals(parar) ){
estado2.setText(R.string.detenido);
isRecording = false;
}
if(v.equals(salir)){
setResult(RESULT_OK);
finish();
}
}
@Override
public void run() {
int posicionActual = 0;
int total = mp.getDuration();
while(mp!=null && posicionActual<total){
try {
Thread.sleep(1000);
posicionActual = mp.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e){
return;
}
progreso.setProgress(posicionActual);
}
}
public void record () {
File file = new
File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/
test.pcm");
// Delete any previous recording.
if (file.exists())
file.delete();
// Create the new file.
try {
file.createNewFile();
} catch (IOException e) {
throw new IllegalStateException("Failed to create " +
file.toString());
}
try {
// Create a DataOuputStream to write the audio data into the
saved file.
OutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
audioRecord.startRecording();
isRecording=true;
while (isRecording) {
int bufferReadResult = audioRecord.read(buffer, 0,
bufferSize);
for (int i = 0; i < bufferReadResult; i++)
dos.writeShort(buffer[i]);
}
audioRecord.stop();
dos.close();
} catch (Throwable t) {
Log.e("AudioRecord","Recording Failed");
}
}
}
----------------------------------------------------------------------------------------------------------
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:background="#00FFFF">
−
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginTop="10px"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold" android:text="@string/estado"
android:typeface="normal" android:textColor="#000000"/>
<TextView android:id="@+id/estado" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_marginTop="10px"
android:textColor="#000000" android:textAppearance="?android:attr/
textAppearanceMedium" android:text="@string/detenido"/>
</LinearLayout>
<ProgressBar android:id="@+id/progreso" style="?android:attr/
progressBarStyleHorizontal" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_marginTop="10px"
android:layout_marginLeft="30px" android:layout_marginRight="30px"
android:max="100" android:progress="0" android:visibility="gone"/>
−
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="@+id/reproducir"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textAppearance="?
android:attr/textAppearanceMedium" android:layout_marginTop="10px"
android:layout_marginLeft="50px" android:layout_marginRight="50px"
android:text="@string/reproducir"/>
<Button android:id="@+id/detener" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textAppearance="?
android:attr/textAppearanceMedium" android:layout_marginTop="10px"
android:layout_marginLeft="50px" android:layout_marginRight="50px"
android:text="@string/detener"/>
</LinearLayout>
−
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginTop="10px"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold" android:text="@string/estado"
android:textColor="#000000"/>
<TextView android:id="@+id/estado2" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_marginTop="10px"
android:textColor="#000000" android:textAppearance="?android:attr/
textAppearanceMedium" android:text="@string/detenido"/>
</LinearLayout>
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="@+id/grabar" android:text="@string/grabar"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textAppearance="?
android:attr/textAppearanceMedium" android:layout_marginTop="10px"
android:layout_marginLeft="50px" android:layout_marginRight="50px"/>
<Button android:id="@+id/parar" android:text="@string/parar"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textAppearance="?
android:attr/textAppearanceMedium" android:layout_marginTop="10px"
android:layout_marginLeft="50px" android:layout_marginRight="50px"/>
<Button android:id="@+id/salir" android:text="@string/salir"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:textAppearance="?
android:attr/textAppearanceMedium" android:layout_marginTop="10px"
android:layout_marginLeft="50px" android:layout_marginRight="50px"/>
</LinearLayout>
</LinearLayout>
----------------------------------------------------------------------------------------------------
<resources>
<string name="estado">Estado: </string>
<string name="estado2">Estado: </string>
<string name="app_name">Reproductor</string>
<string name="detenido">Detenido</string>
<string name="reproduciendo">Reproduciendo</string>
<string name="grabando">Grabando</string>
<string name="reproducir">Reproducir</string>
<string name="detener">Detener</string>
<string name="grabar">Grabar</string>
<string name="parar">Parar</string>
<string name="salir">Salir</string>
</resources>
No entiendo el porque una vez pulso el botón GRABAR, queda
imposiblitado el pulsar otros.
He probado de realizarlos sin los botones REPRODUCIR/DETENER que son
los que lanzan el Thread, y probando de lanzar un thread cuando quiero
grabar, pero entonces no se me crea el archivo.
Agradecería un poco de ayuda, porque estoy realmente estancado, en
algo que no debería suponer un problema.
Gracias de antemano.
Convengo contigo que el problema esta en el while, no hay tutía, esta
grabando y no hace otra cosa.
Para solventar esto, yo a primera vista hubiera intentado usar un
timer o un thread para que no afectara al flujo principal de la
aplicación.
Pero según he visto en la documentación, la gente que hizo Android y
su SDK lo hicieron muy bien.
AudioRecord contiene la posibilidad de indicar que quieres un evento
que cada X frames o cada cierto hito se lance y así poder grabar tu
buffer al fichero.
setPositionNotificationPeriod
De esta forma no coparas el sistema y de camino ahorraras batearías.
> -
> <LinearLayout android:orientation="horizontal"
> android:layout_width="fill_parent"
> android:layout_height="wrap_content">
> <TextView android:layout_width="wrap_content"
> android:layout_height="wrap_content" android:layout_marginTop="10px"
> android:textAppearance="?android:attr/textAppearanceMedium"
> android:textStyle="bold" android:text="@string/estado"
> android:typeface="normal" android:textColor="#000000"/>
> <TextView android:id="@+id/estado" android:layout_width="fill_parent"
> android:layout_height="wrap_content" android:layout_marginTop="10px"
> android:textColor="#000000" android:textAppearance="?android:attr/
> textAppearanceMedium" android:text="@string/detenido"/>
> </LinearLayout>
> <ProgressBar android:id="@+id/progreso" style="?android:attr/
> progressBarStyleHorizontal" android:layout_width="fill_parent"
> android:layout_height="wrap_content" android:layout_marginTop="10px"
> android:layout_marginLeft="30px" android:layout_marginRight="30px"
> android:max="100" android:progress="0" android:visibility="gone"/>
> -
> <LinearLayout android:orientation="vertical"
> android:layout_width="fill_parent"
> android:layout_height="wrap_content">
> <Button android:id="@+id/reproducir"
> android:layout_width="fill_parent"
> android:layout_height="wrap_content" android:textAppearance="?
> android:attr/textAppearanceMedium" android:layout_marginTop="10px"
> android:layout_marginLeft="50px" android:layout_marginRight="50px"
> android:text="@string/reproducir"/>
> <Button android:id="@+id/detener" android:layout_width="fill_parent"
> android:layout_height="wrap_content" android:textAppearance="?
> android:attr/textAppearanceMedium" android:layout_marginTop="10px"
> android:layout_marginLeft="50px" android:layout_marginRight="50px"
> android:text="@string/detener"/>
> </LinearLayout>
> -
Sigo teniendo el mismo problema, no creo que sepa utilizar bien el
método que propones.
He estado buscando ejemplos pero no consigo encontrar la solución.
El caso, es que me está bien que el programa grabe todo el tiempo que
quiera, pero necesito tener una opción a pararlo.
Conoces alguna solución, para que mientras el programa está
registrando el sonido en el fichero, también pueda escuchar la
pulsación de botones.
Como cambiarías el while??
Porque si lo suprimo, no se graba nada en el fichero...:S
Siento ser tan pesado, y entener tan poco...
Gracias nuevamente :)
Otro método es usar un timer para levantar un evento cada x segundos
que haga la lectura del buffer o un thread...
Pero si el SDK da la opción...
antes de iniciar la grabacion indica estos valores, el ultimo no tengo
claro si es necesario, pero como tampoco tengo el codigo a mano no me
voy a meter a modificarlo
audioRecord.setRecordPositionUpdateListener(mNotification);
audioRecord.setPositionNotificationPeriod(50);
audioRecord.setNotificationMarkerPosition(AUDIO_SAMPLE_FREQ);
mNotificacion es un listener que crearas después fuera de tu función
grabar (como los handler de los eventos de clicks o timer)
public OnRecordPositionUpdateListener mNotification = new
OnRecordPositionUpdateListener(){
public void onMarkerReached(AudioRecord arg0) {
// lees el buffer y lo grabas en el file
}
}
En teoria estas indicando que el listener es mNotification, y que el
periodo de notificación es de 50frames (dependerá de la calidad la
captura cuanto equivale eso en segundos).
Sigo sin entender que hace el tercer parámetro, porque no encuentro
parecido entre la documentación o los parámetros de los ejemplos.
Ya casi lo tienes
Ahora mismo me voy a pelear con lo que propones, llevo un rato
probando estas funciones, pero como soy demasiado novel, me
pierdo...xD
Seguiré tus indicaciones, y mañana te comento que tal han ido las
pruebas nocturnas jejeje.
Otra vez, y sin querer ser repetitivo, gracias por tu ayuda, muchos
programadores, tanto experimentados como noveles, deberían aprender de
gente como tu, que brinda su ayuda desinteresada a aquellos que lo
único que buscan es aprender.
:)
Las cosas que voy aprendiendo (una vez las tengo lo bastante claro)
las publico a modo de tutoriales en mi blog
http://schezard.xtreemhost.com/blog/blogs/
Si quieres colaborar a la red, no estaría de mas que cuando dominaras
el AudioRecord hicieras un tutorial para compartirlo con todos (en
este grupo y fuera de el)
Finalmente lo logré!!!
Al final lo he hecho mediante threads, que me ha sido más fácil, pero
lo logré :)
Ahora sólo tengo un pequeño problema, el tema es que cuando hago una
grabación, al inicio de esta me encuentro que hay un fragmento de la
grabación anterior, cuyo fragmento no se encuentra al final del
anterior.
Es como si los buffers en las últimas iteraciones del primer archivo
se llenen pero no graben en el file, y en el segundo archivo, estas
muestras son las primeras que se copian.
He hecho un "for "limpiador" pero ni por esas, luego volveré a echarle
un ojo.
Muchas gracias por tu ayuda, y felicitarte por la página web ;) creo
que me servirá de gran ayuda, y no dudes que colaboraré activamente,
por el momento te contacto para que me unas en la red.
Un saludo.
(Si sabes una solución obvia al problema que te planteo no dudes en
hacermela llegar)
Te adjunto el código del programa, por si te es de utilidad, en cuanto
tenga un buen dominio, no dudes que haré un tutorial.
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.AudioRecord.OnRecordPositionUpdateListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ReproductorMusica extends Activity implements
OnClickListener {
private static final int AUDIO_SAMPLE_FREQ = 8000;
private static final int AUDIO_BUFFER_SIZE = 200000;
private byte [] buffer = null;
private int bytesRead;
private static final int AUDIO_BUFFER_READ_SIZE = 3200;
private boolean recording;
private Thread mThread;
private static AudioRecord ar;
private static AudioTrack at;
private int offset = 0;
private TextView estado2;
private Button grabar;
private Button parar;
private Button salir;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
recording = false;
estado2 = (TextView) findViewById(R.id.estado2);
grabar = (Button) findViewById(R.id.grabar);
salir = (Button) findViewById(R.id.salir);
parar = (Button) findViewById(R.id.parar);
grabar.setOnClickListener(this);
parar.setOnClickListener(this);
salir.setOnClickListener(this);
}
public void onClick(View v) {
if(v.equals(grabar)){
estado2.setText(R.string.grabando);
buffer = new byte[3200];
for(int i=0;i<3200;i++)
buffer[i]=0;
mThread = new Thread(mRunnable);
ar.startRecording();
bytesRead = 3200;
recording = true;
mThread.start();
}
if(v.equals(parar) ){
estado2.setText(R.string.detenido);
//at.stop();
ar.stop();
recording = false;
ar.release();
Log.i("--EARL--", "Recording Stopped");
}
if(v.equals(salir)){ // AHORA ES SETUP
setupAudioRecorder();
}
}
public void setupAudioRecorder()
{
try {
ar = new AudioRecord(MediaRecorder.AudioSource.MIC,
AUDIO_SAMPLE_FREQ,
AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT,
AUDIO_BUFFER_SIZE);
Log.i("--EARL--", "AudioRecord object created");
}catch(Exception e) { Log.i("--EARL--", e.getMessage()); }
}
public static AudioRecord getAudioRecordInstance()
{
return ar;
}
private Runnable mRunnable = new Runnable() {
public void run()
{
File file = new
File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/
test.pcm");
// Delete any previous recording.
if (file.exists())
file.delete();
// Create the new file.
try {
file.createNewFile();
} catch (IOException e) {
throw new IllegalStateException("Failed to create " +
file.toString());
}
try {
// Create a DataOuputStream to write the audio data into the
saved file.
OutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
//at.play();
while(recording)
{
/*try {
Thread.currentThread().sleep(22);
}catch(Exception e) { }*/
if (bytesRead == AUDIO_BUFFER_READ_SIZE &&
ar.getRecordingState
() == AudioRecord.RECORDSTATE_RECORDING)
{
bytesRead = ar.read(buffer, 0,
3200);
dos.write(buffer);
//at.write(buffer, 0, 3200);
Log.i("--EARL--", "Audio Record : " +
bytesRead + " read");
};
}
Te puedes encontrar con que el thread para, pero tienes datos en el
buffer que aun no han pasado por la grabación.
Si haces la lectura del buffer cada n segundos.
prueba a una vez parada la grabación, terminar de limpiar el buffer al
fichero (que realmente pertenece a lo que ha querido grabar el
usuario)
Una vez ya conseguida la captura del audio y estando almacenada en un
fichero .PCM, me interesaría poder medir visualmente la señal que se
graba, es decir, me gustaría un una barra métrica vertical, en la cual
se puedan distinguir diferentes niveles y así poder observar la fuerza
de la señal. En otras palabras, mide el volumen de la señal.
También me sería útil ver la onda (waveform) en pantalla, pero creo
que será algo más dificil ya que se deberá hacer un procesado de audio
mediante FFT.
Una referencia buena de lo que quiero conseguir es el programa
Audalyzer, entre otros.
Cualquier sugerencia o pauta que se les ocurra será de gran ayuda para
mí ya que nuevamente me quedo encallado en este apartado.
Gracias de antemano!
Hola! Disculpen, estoy empezando con Android y quiero desarrollar un afinador de guitarra, para lo cual necesito, de alguna forma, capturar audio mediante el micrófono de mi dispositivo, y después mostrar el valor de la frecuencia de ese sonido. Lo que no sé es cómo hacerlo. Estuve leyendo en varios foros en los cuales sugerían el paquete libgdx, pero ya he estado revisando vídeo tutoriales y varios sitios web y no encuentro nada que me sirva. No sé si alguno de ustedes pueda ilustrarme un poco, por favor.¡Muchas Gracias!
--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/20KhL
---
Has recibido este mensaje porque estás suscrito al grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus correos electrónicos, envía un correo electrónico a desarrolladores-a...@googlegroups.com.
Para publicar una entrada en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.
Para ver este debate en la Web, visita https://groups.google.com/d/msgid/desarrolladores-android/2ebdb63f-3eaf-475c-b55c-23bb53c766ee%40googlegroups.com.
Para obtener más opciones, visita https://groups.google.com/groups/opt_out.