QAudioOutput + FFT + wav
-
Hola amigos. La cuestion es que estoy realizando un proyecto que dado un .wav obtener sus datos y realizarle la FFT. Eso me esta saliendo de maravilla. El problema es a la hora de sincronizar el audio con lo que muestro en pantalla. Le estaba haciendo un .play() normal al audio pero se me desfasa con la FFT a la hora de representarla.
Recien comence a buscar sobre QAudioOutput, que reproduce el buffer de un audio determinado. Si leo el buffer completo, es decir .readAllI() entonces si lo hace, pero si quiero leer poco a poco, las 1024 muestras que envio a la FFT sacarlas a la vez por audio, entonces no me sale. El audio me sale entrecortado, no sale continuo. Aqui les dejo el codigo solamente del QAudioOutput.@
void MyThread::procesarAudio()
{
QFile audio_file("1kHz.wav");
QByteArray audio_data;QAudioFormat format; format.setFrequency(1000); format.setSampleSize(16); format.setSampleRate(44100); format.setChannelCount(1); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); if(audio_file.open(QIODevice::ReadOnly)) { audio_file.seek(44); // skip wav header while((audio_data = audio_file.read(1024))>0) { QBuffer* audio_buffer = new QBuffer(&audio_data); qDebug() << audio_buffer->size(); audio_buffer->open(QIODevice::ReadOnly); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if (!info.isFormatSupported(format)) { qWarning()<<"raw audio format not supported by backend, cannot play audio."; return; } QAudioOutput* output = new QAudioOutput(info, format); output->start(audio_buffer); QEventLoop loop; QObject::connect(output, SIGNAL(stateChanged(QAudio::State)), &loop, SLOT(quit())); do { loop.exec(); } while(output->state() == QAudio::ActiveState); audio_file.seek(1024); } }
}
@ -
Sinceramente, no entiendo que intentas hacer.
Por lo que llego a entender de tu código, lo que haces es abrir un archivo WAV, con cada iteración lees 1024 bytes (sí, bytes, no muestras), ni siquiera estas leyendo las cabeceras del archivo, ni sabes cuantos canales estas reproduciendo, ni la frecuencia de muestreo.
Luego, por cada muestra que lees, abres una y otra vez QAudioOutput, y ni siquiera desalojas la memoria, con lo que tienes un terrible memory leak.
-
Gracias por responder amigo, habia estado un tiempo fuera, por eso mi demora en volver a responder. Sorry.
Mira, lo que quiero hacer es lo siguiente, estoy desarrollando un proyecto de la FFT. Yo leo un .wav y cada 1024 bytes los envio a la FFT y me da un resultado, el cual muestro en pantalla de forma grafica en el espectro de frecuencia. A la hora de sincronizar el audio de ese .wav con lo que muestro en pantalla es el problema, debido a que si le digo sin mas audio->play(); pues en ocasiones sale sincronizado, pero cuando el fichero de audio es muy grande, el audio se discordina respecto a lo que estoy viendo en pantalla.
Por eso la idea de cada vez que lea 1024 bytes de ese .wav, y se los pase a la FFT, pues tambien los pase a la tarjeta de sonido de la PC y lo reproduzca, por lo que quedaria sincronizado.
El codigo de arriba, los valores puestos en el format, son los mismos del .wav que tengo por defecto. Estan puesto estaticos, pero son esos mismos parametros los que tiene el audio que estoy leyendo.
Un saludo y en espera de respuesta.
Gracias por contestar. -
[quote author="Federico Perez" date="1423212394"]
Mira, lo que quiero hacer es lo siguiente, estoy desarrollando un proyecto de la FFT. Yo leo un .wav y cada 1024 bytes los envio a la FFT y me da un resultado,
[/quote]No me estas entendiendo, los archivos wav tienen formato, no se pueden leen por "bytes", primero se debe leer la cabecera y luego extraer la data. Aquí te dejo las "especificaciones del formato":http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html.
"QAudioOutput":http://doc.qt.io/qt-5/qaudiooutput.html solo procesa audio en bruto, no archivos con formato. "QFile":http://doc.qt.io/qt-5/qfile.html tampoco lee formatos, solo sabe que le estas pasando un archivo, pero no sabe como esta compuesto ese archivo.
[quote author="Federico Perez" date="1423212394"]
pues en ocasiones sale sincronizado, pero cuando el fichero de audio es muy grande, el audio se discordina respecto a lo que estoy viendo en pantalla.Por eso la idea de cada vez que lea 1024 bytes de ese .wav, y se los pase a la FFT, pues tambien los pase a la tarjeta de sonido de la PC y lo reproduzca, por lo que quedaria sincronizado.
[/quote]Se discordina por que estas abriendo QOutput cada vez, y por que estas leyendo mal el formato.
[quote author="Federico Perez" date="1423212394"]
El codigo de arriba, los valores puestos en el format, son los mismos del .wav que tengo por defecto. Estan puesto estaticos, pero son esos mismos parametros los que tiene el audio que estoy leyendo.
[/quote]No, están mal, por ejemplo:
@format.setSampleSize(16);@
aquí le estas diciendo que vas a reproducir muestras de 2 bytes, y le estas pasando data de 1 byte.
-
Agh! no me dí cuenta de esto:
@audio_file.seek(44);@
perdón, de cualquier forma, revisa lo de format.setSampleSize y lo de QAudioOutput
-
@
void MyThread::procesarAudio()
{FILE * fp = fopen("1kHz.wav","rb"); char type[4]; int sample_rat; int size, chunkSize; short formatType, channels; int avgBytesPerSec; short bytesPerSample, bitsPerSample; int dataSize; fread(type, sizeof(char), 4, fp); fread(&size, sizeof(int), 1, fp); fread(type, sizeof(char), 4, fp); fread(type, sizeof(char), 4, fp); fread(&chunkSize, sizeof(int), 1, fp); fread(&formatType, sizeof(short), 1, fp); fread(&channels, sizeof(short), 1, fp); fread(&sample_rat, sizeof(int), 1, fp); fread(&avgBytesPerSec, sizeof(int), 1, fp); fread(&bytesPerSample, sizeof(short), 1, fp); fread(&bitsPerSample, sizeof(short), 1, fp); fread(type, sizeof(char), 4, fp); fread(&dataSize, sizeof(int), 1, fp); QFile audio_file("1kHz.wav"); QByteArray audio_data; QAudioFormat format; format.setFrequency(1000); format.setSampleSize(16); format.setSampleRate(44100); format.setChannelCount(1); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if (!info.isFormatSupported(format)) { qWarning()<<"raw audio format not supported by backend, cannot play audio."; return; } QAudioOutput* output = new QAudioOutput(info, format); QEventLoop loop; if(audio_file.open(QIODevice::ReadOnly)) { audio_file.seek(44); // skip wav header while((audio_data = audio_file.read(1024))>0) { // audio_file.close(); QBuffer* audio_buffer = new QBuffer(&audio_data); qDebug() << audio_buffer->size(); audio_buffer->open(QIODevice::ReadOnly); output->start(audio_buffer); QObject::connect(output, SIGNAL(stateChanged(QAudio::State)), &loop, SLOT(quit())); do { loop.exec(); } while(output->state() == QAudio::ActiveState); audio_file.seek(1024); } }
}
@Al inicio del codigo puedes ver como leo todo el encabezado del .wav, eso funciona a las mil maravillas, por eso se los datos de ese fichero en especifico y los pongo de forma estatica en format.
Si deseas puedo subir el codigo fuente del proyecto, tambien el del proyecto completo de la FFT para que veas de primera mano el problema que presentosaludos y gracias por responder.