2010-10-20 34 views
8

Quiero leer un archivo de sonido del paquete de aplicaciones, copiarlo, reproducirlo con su nivel de volumen máximo (valor de ganancia o potencia máxima, no estoy seguro del nombre técnico del mismo), y luego escribirlo como otro archivo en el paquete de nuevo.Procesamiento de audio: Reproducción con nivel de volumen

Hice la parte de copiar y escribir. El archivo resultante es idéntico al archivo de entrada. Utilizo las funciones AudioFileReadBytes() y AudioFileWriteBytes() de los servicios de AudioFile en AudioToolbox framework para hacer eso.

Por lo tanto, tengo los bytes del archivo de entrada y también su formato de datos de audio (mediante el uso de AudioFileGetProperty() con kAudioFilePropertyDataFormat) pero no puedo encontrar una variable para reproducir con el nivel de volumen máximo del archivo original.

Para aclarar mi propósito, estoy tratando de producir otro archivo de sonido cuyo nivel de volumen se incrementa o disminuye en relación con el original, por lo que no me importa el nivel de volumen del sistema que el usuario o iOS.

¿Es eso posible con el marco que mencioné? Si no, ¿hay alguna sugerencia alternativa?

Gracias


edición: Caminando a través de la respuesta de Sam con respecto a algunos conceptos básicos de audio, me decidieron ampliar la pregunta con otra alternativa.

¿Puedo usar los servicios de AudioQueue para grabar un archivo de sonido existente (que está en el paquete) en otro archivo y reproducirlo con el nivel de volumen (con la ayuda de framework) durante la fase de grabación?


actualización: Así es como estoy leyendo el archivo de entrada y escribir la salida. El siguiente código baja el nivel de sonido para "algunos" de los valores de amplitud pero con mucho ruido. Curiosamente, si elijo 0.5 como valor de amplitud, aumenta el nivel de sonido en lugar de bajarlo, pero cuando uso 0.1 como valor de amplitud, baja el sonido. Ambos casos implican un ruido molesto. Creo que es por eso que Art habla de normalización, pero no tengo idea sobre la normalización.

AudioFileID inFileID; 

CFURLRef inURL = [self inSoundURL]; 

AudioFileOpenURL(inURL, kAudioFileReadPermission, kAudioFileWAVEType, &inFileID) 

UInt32 fileSize = [self audioFileSize:inFileID]; 
Float32 *inData = malloc(fileSize * sizeof(Float32)); //I used Float32 type with jv42's suggestion 
AudioFileReadBytes(inFileID, false, 0, &fileSize, inData); 

Float32 *outData = malloc(fileSize * sizeof(Float32)); 

//Art's suggestion, if I've correctly understood him 

float ampScale = 0.5f; //this will reduce the 'volume' by -6db 
for (int i = 0; i < fileSize; i++) { 
    outData[i] = (Float32)(inData[i] * ampScale); 
} 

AudioStreamBasicDescription outDataFormat = {0}; 
[self audioDataFormat:inFileID]; 

AudioFileID outFileID; 

CFURLRef outURL = [self outSoundURL]; 
AudioFileCreateWithURL(outURL, kAudioFileWAVEType, &outDataFormat, kAudioFileFlags_EraseFile, &outFileID) 

AudioFileWriteBytes(outFileID, false, 0, &fileSize, outData); 

AudioFileClose(outFileID); 
AudioFileClose(inFileID); 

Respuesta

13

No encontrará operaciones de escala de amplitud en (Ext) AudioFile, porque se trata del DSP más simple que puede hacer.

Supongamos que utiliza ExtAudioFile para convertir lo que lee en carrozas de 32 bits.Para cambiar la amplitud, simplemente multiplique:

float ampScale = 0.5f; //this will reduce the 'volume' by -6db 
for (int ii=0; ii<numSamples; ++ii) { 
    *sampOut = *sampIn * ampScale; 
    sampOut++; sampIn++; 
} 

Para aumentar la ganancia, simplemente use una escala> 1.f. Por ejemplo, una ampScale de 2.f te da + 6dB de ganancia.

Si desea realizar una normalización, debe realizar dos pasadas sobre el audio: una para determinar la muestra con la mayor amplitud. Luego, otro para aplicar realmente su ganancia calculada.

El uso de los servicios de AudioQueue solo para obtener acceso a la propiedad de volumen es una exageración seria y grave.

ACTUALIZACIÓN:

En su código actualizado, que estás multiplicando cada byte por 0,5 en lugar de cada muestra. Aquí hay una solución rápida y sucia para su código, , pero vea mis notas debajo de. No haría lo que estás haciendo.

... 

// create short pointers to our byte data 
int16_t *inDataShort = (int16_t *)inData; 
int16_t *outDataShort = (int16_t *)inData; 

int16_t ampScale = 2; 
for (int i = 0; i < fileSize; i++) { 
    outDataShort[i] = inDataShort[i]/ampScale; 
} 

... 

Por supuesto, esto no es la mejor manera de hacer las cosas: Se supone que su archivo es ascendente hacia la izquierda de 16 bits con signo PCM lineal. (La mayoría de los archivos WAV son, pero no AIFF, m4a, mp3, etc.) Usaría la API ExtAudioFile en lugar de la API AudioFile, ya que esto convertirá cualquier formato que esté leyendo en cualquier formato con el que desee trabajar en el código. Por lo general, lo más simple es leer las muestras en forma de flotador de 32 bits. He aquí un ejemplo de su código usando ExtAudioAPI para manejar cualquier formato de archivo de entrada, incluyendo estéreo v. Mono

void ScaleAudioFileAmplitude(NSURL *theURL, float ampScale) { 
    OSStatus err = noErr; 

    ExtAudioFileRef audiofile; 
    ExtAudioFileOpenURL((CFURLRef)theURL, &audiofile); 
    assert(audiofile); 

    // get some info about the file's format. 
    AudioStreamBasicDescription fileFormat; 
    UInt32 size = sizeof(fileFormat); 
    err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_FileDataFormat, &size, &fileFormat); 

    // we'll need to know what type of file it is later when we write 
    AudioFileID aFile; 
    size = sizeof(aFile); 
    err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_AudioFile, &size, &aFile); 
    AudioFileTypeID fileType; 
    size = sizeof(fileType); 
    err = AudioFileGetProperty(aFile, kAudioFilePropertyFileFormat, &size, &fileType); 


    // tell the ExtAudioFile API what format we want samples back in 
    AudioStreamBasicDescription clientFormat; 
    bzero(&clientFormat, sizeof(clientFormat)); 
    clientFormat.mChannelsPerFrame = fileFormat.mChannelsPerFrame; 
    clientFormat.mBytesPerFrame = 4; 
    clientFormat.mBytesPerPacket = clientFormat.mBytesPerFrame; 
    clientFormat.mFramesPerPacket = 1; 
    clientFormat.mBitsPerChannel = 32; 
    clientFormat.mFormatID = kAudioFormatLinearPCM; 
    clientFormat.mSampleRate = fileFormat.mSampleRate; 
    clientFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved; 
    err = ExtAudioFileSetProperty(audiofile, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat); 

    // find out how many frames we need to read 
    SInt64 numFrames = 0; 
    size = sizeof(numFrames); 
    err = ExtAudioFileGetProperty(audiofile, kExtAudioFileProperty_FileLengthFrames, &size, &numFrames); 

    // create the buffers for reading in data 
    AudioBufferList *bufferList = malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (clientFormat.mChannelsPerFrame - 1)); 
    bufferList->mNumberBuffers = clientFormat.mChannelsPerFrame; 
    for (int ii=0; ii < bufferList->mNumberBuffers; ++ii) { 
     bufferList->mBuffers[ii].mDataByteSize = sizeof(float) * numFrames; 
     bufferList->mBuffers[ii].mNumberChannels = 1; 
     bufferList->mBuffers[ii].mData = malloc(bufferList->mBuffers[ii].mDataByteSize); 
    } 

    // read in the data 
    UInt32 rFrames = (UInt32)numFrames; 
    err = ExtAudioFileRead(audiofile, &rFrames, bufferList); 

    // close the file 
    err = ExtAudioFileDispose(audiofile); 

    // process the audio 
    for (int ii=0; ii < bufferList->mNumberBuffers; ++ii) { 
     float *fBuf = (float *)bufferList->mBuffers[ii].mData; 
     for (int jj=0; jj < rFrames; ++jj) { 
      *fBuf = *fBuf * ampScale; 
      fBuf++; 
     } 
    } 

    // open the file for writing 
    err = ExtAudioFileCreateWithURL((CFURLRef)theURL, fileType, &fileFormat, NULL, kAudioFileFlags_EraseFile, &audiofile); 

    // tell the ExtAudioFile API what format we'll be sending samples in 
    err = ExtAudioFileSetProperty(audiofile, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat); 

    // write the data 
    err = ExtAudioFileWrite(audiofile, rFrames, bufferList); 

    // close the file 
    ExtAudioFileDispose(audiofile); 

    // destroy the buffers 
    for (int ii=0; ii < bufferList->mNumberBuffers; ++ii) { 
     free(bufferList->mBuffers[ii].mData); 
    } 
    free(bufferList); 
    bufferList = NULL; 

} 
+0

Gracias Art. He actualizado mi código y la pregunta de acuerdo con su sugerencia, pero esto causó otros problemas. Quizás te equivoqué, pero será perfecto si puedes mirar la pregunta actualizada con fragmento de código. – cocoatoucher

+0

He editado mi respuesta con una explicación de por qué su código no funciona y un ejemplo de código que lo hará. –

+0

Arte, estoy agradecido por esta respuesta. No solo me proporcionó el código sino que también me ayudó a comprender lo que está sucediendo. ¡Muchas gracias! Por favor sigue compartiendo Gracias a otras personas también. – cocoatoucher

0

Para los formatos de archivo de audio más comunes, no hay una sola variable de volumen principal. En su lugar, deberá tomar (o convertir) las muestras de sonido PCM y realizar al menos un procesamiento de señal digital mínimo (multiplicar, saturar/limitar/AGC, conformar el ruido de cuantificación, etc.) en cada muestra.

+0

eso es una mala noticia :) Preferiría que el marco maneje tales operaciones científicas si es necesario :) – cocoatoucher

0

Si el archivo de sonido está normalizado, no hay nada que pueda hacer para que el archivo sea más ruidoso. Excepto en el caso de audio mal codificado, el volumen es casi completamente el dominio del motor de reproducción.

http://en.wikipedia.org/wiki/Audio_bit_depth

archivos de audio almacenados correctamente tendrán volumen máximo en o cerca del valor máximo disponible para la profundidad de bits del archivo. Si intenta 'disminuir el volumen' de un archivo de sonido, básicamente estará degradando la calidad del sonido.

+0

Gracias, eso tiene sentido. Luego, tengo que expandir la pregunta y compartir mis propias alternativas. – cocoatoucher

1

Creo que debería evitar trabajar con 8 bits de caracteres sin signo para el audio, si es posible. Trate de obtener los datos como 16 bits o 32 bits, eso evitaría algunos problemas de ruido/mala calidad.

+0

Gracias, lo intenté con Float32 pero todavía tengo un ruido similar – cocoatoucher

Cuestiones relacionadas