9

アプリケーションバンドルからサウンドファイルを読み取り、コピーして、最大音量レベル(ゲイン値またはピークパワー、技術的な名前はわかりません)で再生してから、別のファイルとしてバンドルに書き込みます。また。

コピーと書き込みの部分を行いました。結果のファイルは入力ファイルと同じです。これを行うには、AudioToolboxフレームワークのAudioFileサービスのAudioFileReadBytes()関数とAudioFileWriteBytes()関数を使用します。

したがって、入力ファイルのバイトとそのオーディオデータ形式(kAudioFilePropertyDataFormatでAudioFileGetProperty()を使用)がありますが、元のファイルの最大音量レベルで再生する変数がこれらに見つかりません。

目的を明確にするために、元の音量レベルに比べて音量レベルを上げたり下げたりする別のサウンドファイルを作成しようとしているので、ユーザーやiOSによって設定されるシステムの音量レベルは気にしません。

私が言及したフレームワークでそれを行うことは可能ですか?そうでない場合、代替案はありますか?

ありがとう


編集:いくつかのオーディオの基本に関するサムの答えを見て、私は別の選択肢で質問を拡張することにしました。

AudioQueueサービスを使用して、既存のサウンドファイル(バンドルに含まれている)を別のファイルに録音し、録音フェーズ中に音量レベル(フレームワークを使用)で再生できますか?


更新:これが、入力ファイルの読み取りと出力の書き込みの方法です。以下のコードは、振幅値の「一部」のサウンドレベルを下げますが、ノイズが多くなります。興味深いことに、振幅値として0.5を選択すると、サウンドレベルが下がるのではなく増加しますが、振幅値として0.1を使用すると、サウンドが下がります。どちらの場合も、不快なノイズが発生します。アートが正規化について話しているのはそのためだと思いますが、正規化についてはわかりません。

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

4 に答える 4

16

(Ext)AudioFileには、実行できる最も単純なDSPに関するものであるため、振幅スケーリング操作はありません。

ExtAudioFileを使用して、読み取ったものを32ビットのfloatに変換するとします。振幅を変更するには、単純に次のように乗算します。

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

ゲインを上げるには、スケール>1.fを使用するだけです。たとえば、ampScaleが2.fの場合、+6dBのゲインが得られます。

正規化する場合は、オーディオに対して2つのパスを作成する必要があります。1つは、最大振幅のサンプルを決定するためです。次に、計算されたゲインを実際に適用するための別の方法。

ボリュームプロパティにアクセスするためだけにAudioQueueサービスを使用することは、深刻で深刻なやり過ぎです。

アップデート:

更新されたコードでは、各サンプルではなく、各バイトに0.5を掛けています。これがあなたのコードの手っ取り早い修正ですが、以下の私のメモを見てください。私はあなたがしていることをしません。

...

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

...

もちろん、これは最善の方法ではありません。ファイルがリトルエンディアンの16ビット符号付き線形PCMであると想定しています。(ほとんどのWAVファイルはAIFF、m4a、mp3などではありません。)AudioFileAPIの代わりにExtAudioFileAPIを使用します。これにより、読み取っている形式がコードで使用する形式に変換されます。通常、最も簡単な方法は、サンプルを32ビット浮動小数点数として読み込むことです。ExtAudioAPIを使用して、ステレオv。モノラルを含む任意の入力ファイル形式を処理するコードの例を次に示します。

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;

}
于 2010-10-20T23:10:27.687 に答える
1

可能であれば、オーディオ用に8ビットのunsignedcharを使用することは避けるべきだと思います。データを16ビットまたは32ビットとして取得してみてください。これにより、ノイズや品質の低下の問題を回避できます。

于 2010-10-21T14:14:18.530 に答える
0

最も一般的なオーディオファイル形式の場合、単一のマスターボリューム変数はありません。代わりに、PCMサウンドサンプルを取得(または変換)し、各サンプルで少なくともいくつかの最小限のデジタル信号処理(乗算、飽和/制限/ AGC、量子化ノイズシェーピングなど)を実行する必要があります。

于 2010-10-20T22:17:54.797 に答える
0

サウンドファイルが正規化されている場合、ファイルを大きくするためにできることは何もありません。エンコードが不十分なオーディオの場合を除いて、音量はほぼ完全に再生エンジンの領域です。

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

適切に保存されたオーディオファイルのピークボリュームは、ファイルのビット深度で使用可能な最大値またはその近くになります。サウンドファイルの「音量を下げる」ことを試みると、本質的に音質が低下するだけです。

于 2010-10-20T22:18:46.397 に答える