2010-10-20 8 views
8

Ich möchte eine Sounddatei aus dem Anwendungspaket lesen, kopieren, mit der maximalen Lautstärke abspielen (Verstärkungswert oder Spitzenleistung, ich bin mir nicht sicher über den technischen Namen), und schreiben Sie es dann erneut als eine andere Datei in das Bundle.Audio Processing: Wiedergabe mit Lautstärkepegel

Ich habe das Kopieren und Schreiben Teil. Die resultierende Datei ist identisch mit der Eingabedatei. Ich verwende AudioFileReadBytes() und AudioFileWriteBytes() - Funktionen von AudioFile-Diensten im AudioToolbox-Framework, um dies zu tun.

So habe ich die Bytes der Eingabedatei und auch sein Audiodatenformat (über die Verwendung von AudioFileGetProperty() mit kAudioFilePropertyDataFormat), aber ich kann keine Variable in diesen finden, um mit der maximalen Lautstärke der ursprünglichen Datei zu spielen.

mein Ziel Um zu klären, ich versuche, einen anderen Sound-Datei von dem Lautstärkepegel verringert wird, erhöht zu produzieren oder zu dem ursprünglichen Verwandten, so dass ich kümmere mich nicht um die Lautstärke des Systems, die vom Benutzer eingestellt oder iOS.

Ist das möglich mit dem Framework, das ich erwähnt habe? Wenn nicht, gibt es alternative Vorschläge?

Dank


edit: durch Antwort in Bezug auf einigen Audio-Grundlagen Sam Gehen, habe ich beschlossen, die Frage mit einer anderen Alternative zu erweitern.

Kann ich AudioQueue-Dienste verwenden, um eine vorhandene Audiodatei (die im Paket enthalten ist) in eine andere Datei aufzunehmen und während der Aufnahme mit der Lautstärke (mit Hilfe von Framework) zu spielen?


Update: Hier ist, wie ich die Eingabedatei zu lesen und die Ausgabe zu schreiben. Der folgende Code senkt den Lautstärkepegel für "einige" der Amplitudenwerte, jedoch mit viel Rauschen. Interessant ist, wenn ich 0,5 als Amplitudenwert wähle, erhöht sich der Schallpegel, anstatt ihn zu verringern, aber wenn ich 0,1 als Amplitudenwert verwende, wird der Ton gesenkt. In beiden Fällen treten störende Geräusche auf. Ich denke, deshalb spricht Art über Normalisierung, aber ich habe keine Ahnung von Normalisierung.

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); 

Antwort

13

Sie finden keine Amplitudenskalierung in (Ext) AudioFile, weil es sich um die einfachste DSP handelt, die Sie tun können.

Angenommen, Sie verwenden ExtAudioFile, um das, was Sie lesen, in 32-Bit-Floats zu konvertieren.Um die Amplitude zu ändern, multiplizieren Sie einfach:

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

Um die Verstärkung zu erhöhen, verwenden Sie einfach eine Skala> 1.f. Zum Beispiel würde eine AmpScale von 2.f Ihnen + 6dB Verstärkung geben.

Wenn Sie normalisieren möchten, müssen Sie zwei Übergänge über das Audio machen: Eines, um das Sample mit der größten Amplitude zu bestimmen. Dann eine andere, um Ihren berechneten Gewinn tatsächlich anzuwenden.

Die Verwendung von AudioQueue-Diensten, nur um Zugriff auf die Volume-Eigenschaft zu erhalten, ist ernst, ernster Overkill.

UPDATE:

In Ihrem aktualisierten Code, Sie Multiplizieren jedes Byte um 0,5 statt jeder Probe. Hier ist eine schnelle und dreckige Lösung für Ihren Code, , aber sehen Sie meine Notizen unter. Ich würde nicht tun, was du tust.

... 

// 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; 
} 

... 

Natürlich ist dies nicht der beste Weg, Dinge zu tun: Es nimmt an Ihrer Datei ist Little-Endian-16-Bit-Linear-PCM unterzeichnet. (Die meisten WAV-Dateien sind, aber nicht AIFF, m4a, mp3 usw.) Ich würde die ExtAudioFile-API anstelle der AudioFile-API verwenden, da dies jedes Format, das Sie lesen, in das Format konvertiert, mit dem Sie im Code arbeiten möchten. Normalerweise ist es am einfachsten, Ihre Samples als 32-Bit-Float zu lesen. Hier ist ein Beispiel des Codes ExtAudioAPI jedes Eingabe-Dateiformat zu behandeln verwenden, einschließlich Stereo 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

Danke Kunst, ich habe sowohl meinen Code als auch die Frage entsprechend Ihrem Vorschlag aktualisiert, aber das verursachte andere Probleme. Vielleicht habe ich dich falsch verstanden, aber es ist perfekt, wenn du dir die aktualisierte Frage mit Codeausschnitt ansehen kannst. – cocoatoucher

+0

Ich habe meine Antwort mit einer Erklärung, warum Ihr Code nicht funktioniert, und ein Beispiel für Code, der das tut, bearbeitet. –

+0

Kunst, ich bin dankbar für diese Antwort. Sie haben mir nicht nur den Code zur Verfügung gestellt, sondern mir auch geholfen zu verstehen, was vor sich geht. Danke vielmals! Bitte teilen Sie weiter. Danke auch an andere Leute. – cocoatoucher

0

Für die meisten gebräuchlichen Audiodateiformate gibt es keine einzige Hauptlautstärkenvariable. Stattdessen müssen Sie die PCM-Sound-Samples nehmen (oder konvertieren) und mindestens eine minimale digitale Signalverarbeitung (Multiplizieren, Sättigen/Begrenzen/AGC, Quantisierungs-Noise-Shaping usw.) für jede Probe durchführen.

+0

das sind schlechte Nachrichten :) Ich würde das Framework behandeln solche wissenschaftlichen Operationen wenn nötig bevorzugen :) – cocoatoucher

0

Wenn die Audiodatei normalisiert ist, können Sie nichts tun, um die Datei lauter zu machen. Abgesehen von schlecht kodiertem Audio ist die Lautstärke fast ausschließlich der Bereich der Wiedergabe-Engine.

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

ordnungsgemäß gespeicherten Audiodateien werden an oder nahe dem Maximalwert vorhanden Spitzenvolumen haben für die Bit-Tiefe der Datei. Wenn Sie versuchen, die Lautstärke einer Audiodatei zu verringern, verschlechtern Sie die Klangqualität.

+0

Danke, das macht Sinn. Dann muss ich die Frage erweitern und meine eigenen Alternativen teilen. – cocoatoucher

1

Ich denke, Sie sollten es vermeiden, mit 8 Bit unsigned Zeichen für Audio arbeiten, wenn Sie können. Versuchen Sie, die Daten als 16 Bit oder 32 Bit zu erhalten, um Probleme mit Rauschen und schlechter Qualität zu vermeiden.

+0

Danke, ich habe versucht mit Float32, aber ich habe immer noch ähnliche Geräusche – cocoatoucher