音频处理:有音量级别播放 [英] Audio Processing: Playing with volume level

查看:379
本文介绍了音频处理:有音量级别播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想读从应用程序中捆绑的声音文件,复制,发挥其最大音量级别(增益值或峰值功率,我不知道它的技术名称),然后把它写成另一个文件将捆绑一次。

我做的复制和写作部分。得到的文件是相同的输入文件。我用AudioFileReadBytes()和AudioFileWriteBytes()中的AudioFile服务功能AudioToolbox框架来做到这一点。

所以,我有输入文件的字节而且其音频数据格式(通过使用AudioFileGetProperty(中)与kAudioFilePropertyDataFormat),但我找不到这些变量与原始文件的最大音量播放。

要澄清我的目的,我想生产出的音量电平增加或到原来的下降相对另一个声音文件,所以我不关心这是由用户或iOS设置系统的音量

这有可能是与我提到的框架?如果不是,是否有任何其他建议?

感谢


编辑:
通过山姆对于一些基本的音响散步的答案,我决定扩大与另一种选择的问题。

可否使用AudioQueue服务来记录现有的声音文件(它是在束)到另一个文件和音量播放(具有框架的帮助下)期间在记录相位θ


更新:
以下是我正在读输入文件写入输出。低于code降低了幅度值一些,但有很多噪声的声级。有趣的是,如果我选择0.5振幅值会增加音量,而不是降低了,但是当我使用0.1振幅值它降低了声音。这两个案件涉及干扰噪声。我想这就是为什么艺术在谈论正常化,但我没有对规范化的想法。

  AudioFileID inFileID;CFURLRef INURL = [个体经营inSoundURL]AudioFileOpenURL(INURL,kAudioFileReadPermission,kAudioFileWAVEType,&安培; inFileID)UInt32的档案大小= [自我audioFileSize:inFileID];
FLOAT32 * INDATA =的malloc(档案大小*的sizeof(浮点32)); //我用浮点32型与jv42的建议
AudioFileReadBytes(inFileID,假,0,&安培;档案大小,INDATA);FLOAT32 * outData =的malloc(档案大小*的sizeof(浮点32));//艺术的建议,如果我理解正确的话他浮ampScale = 0.5F; //这将减少-6dB音量
的for(int i = 0; I<档案大小,我++){
    outData [I] =(浮点32)(INDATA [I] * ampScale);
}AudioStreamBasicDescription outDataFormat = {0};
[个体经营audioDataFormat:inFileID];AudioFileID outFileID;CFURLRef outURL = [个体经营outSoundURL]
AudioFileCreateWithURL(outURL,kAudioFileWAVEType,&安培; outDataFormat,kAudioFileFlags_EraseFile,&安培; outFileID)AudioFileWriteBytes(outFileID,假,0,&安培;档案大小,outData)以;AudioFileClose(outFileID);
AudioFileClose(inFileID);


解决方案

您不会找到(EXT)的AudioFile幅度缩放操作,因为它是你可以做最简单的DSP。

让我们假设你使用ExtAudioFile,无论你读入32位浮点数转换。要改变幅度,您只需乘:

 浮动ampScale = 0.5F; //这将减少-6dB音量
为(中间体二= 0; II蛋白酶NUMSAMPLES ++ⅱ){
    * sampOut = * sampIn * ampScale;
    sampOut ++; sampIn ++;
}

要提高增益,您只需使用一个规模> 1.f.例如,2.F的ampScale会给你+ 6dB的增益。

如果你想正常化,就必须进行两次越过音频:一是确定以最大的幅度的样本。然后又到实际应用的计算出的增益。

使用AudioQueue服务只是为了获得访问卷属性是严肃,认真矫枉过正。

更新:

在更新后的code,你是0.5,而不是每个采样乘以每个字节的。这里有一个快速和肮脏的修复您的code,的见下文的我的笔记。我不会做你在做什么。

  ...//创建短指向我们的数据字节
int16_t * inDataShort =(int16_t *)INDATA;
int16_t * outDataShort =(int16_t *)INDATA;int16_t ampScale = 2;
的for(int i = 0; I<档案大小,我++){
    outDataShort [I] = inDataShort [I] / ampScale;
}...

当然,这不是做事情的最好方法:假定你的文件是little-endian的16位有符号的线性PCM。 (大多数WAV文件,但不AIFF,M4A,MP3等)我会使用的ExtAudioFile API而不是API的AudioFile的,因为这将转换成你读成你想要用$ C工作的任何格式的任何格式$ C。通常做最简单的事情是读你的样品中为32位浮点。下面是使用ExtAudioAPI来处理任何输入文件格式,包括立体声v您code的一个例子。单

 无效ScaleAudioFileAmplitude(NSURL * theURL,浮动ampScale){
    OSStatus ERR =诺尔;    ExtAudioFileRef的AudioFile;
    ExtAudioFileOpenURL((CFURLRef)theURL,&安培; audiofile的);
    断言(audiofile的);    //获取有关文件的格式一些信息。
    AudioStreamBasicDescription FILEFORMAT;
    UInt32的大小= sizeof的(FILEFORMAT);
    ERR = ExtAudioFileGetProperty(的AudioFile,kExtAudioFileProperty_FileDataFormat,&安培;大小,和放大器; FILEFORMAT);    //我们需要知道它是什么类型的文件后,当我们写
    AudioFileIDå文件;
    大小= sizeof的(å文件);
    ERR = ExtAudioFileGetProperty(的AudioFile,kExtAudioFileProperty_AudioFile,&安培;大小,和放大器;å文件);
    AudioFileTypeID的fileType;
    大小= sizeof的(的fileType);
    ERR = AudioFileGetProperty(å文件,kAudioFilePropertyFileFormat,&安培;大小,和放大器;的fileType);
    //告诉ExtAudioFile API什么格式,我们希望样本回
    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);    //找出我们需要多少帧阅读
    SInt64 numFrames = 0;
    大小= sizeof的(numFrames);
    ERR = ExtAudioFileGetProperty(的AudioFile,kExtAudioFileProperty_FileLengthFrames,&安培;大小,和放大器; numFrames);    //创建缓冲区中读取数据
    AudioBufferList * bufferList = malloc的(的sizeof(AudioBufferList)+ sizeof的(AudioBuffer)*(clientFormat.mChannelsPerFrame - 1));
    bufferList-> mNumberBuffers = clientFormat.mChannelsPerFrame;
    为(中间体二= 0; II蛋白酶bufferList-> mNumberBuffers ++ⅱ){
        bufferList-> mBuffers [II] .mDataByteSize = sizeof的(浮点)* numFrames;
        bufferList-> mBuffers [Ⅱ] .mNumberChannels = 1;
        bufferList-> mBuffers [Ⅱ] .mData = malloc的(bufferList-> mBuffers [Ⅱ] .mDataByteSize);
    }    //读取的数据
    UInt32的rFrames =(UInt32的)numFrames;
    ERR = ExtAudioFileRead(的AudioFile,&安培; rFrames,bufferList);    //关闭文件
    ERR = ExtAudioFileDispose(audiofile的);    //处理的声音
    为(中间体二= 0; II蛋白酶bufferList-> mNumberBuffers ++ⅱ){
        浮动* fBuf =(浮点*)bufferList-> mBuffers [II] .mData;
        对于(INT JJ = 0; JJ< rFrames ++ JJ){
            * fBuf = * fBuf * ampScale;
            fBuf ++;
        }
    }    //打开书面文件
    ERR = ExtAudioFileCreateWithURL((CFURLRef)theURL,文件类型,和放大器; FILEFORMAT,NULL,kAudioFileFlags_EraseFile,&安培; audiofile的);    //告诉ExtAudioFile API什么格式,我们将中送样
    ERR = ExtAudioFileSetProperty(的AudioFile,kExtAudioFileProperty_ClientDataFormat,sizeof的(clientFormat),放大器; clientFormat);    //写入数据
    ERR = ExtAudioFileWrite(的AudioFile,rFrames,bufferList);    //关闭文件
    ExtAudioFileDispose(audiofile的);    //销毁缓冲区
    为(中间体二= 0; II蛋白酶bufferList-> mNumberBuffers ++ⅱ){
        免费(bufferList-> mBuffers [II] .mData);
    }
    免费(bufferList);
    bufferList = NULL;}

I want to read a sound file from application bundle, copy it, play with its maximum volume level(Gain value or peak power, I'm not sure about the technical name of it), and then write it as another file to the bundle again.

I did the copying and writing part. Resulting file is identical to input file. I use AudioFileReadBytes() and AudioFileWriteBytes() functions of AudioFile services in AudioToolbox framework to do that.

So, I have the input file's bytes and also its audio data format(via use of AudioFileGetProperty() with kAudioFilePropertyDataFormat) but I can't find a variable in these to play with the original file's maximum volume level.

To clarify my purpose, I'm trying to produce another sound file of which volume level is increased or decreased relative to the original one, so I don't care about the system's volume level which is set by the user or iOS.

Is that possible to do with the framework I mentioned? If not, are there any alternative suggestions?

Thanks


edit: Walking through Sam's answer regarding some audio basics, I decided to expand the question with another alternative.

Can I use AudioQueue services to record existing sound file(which is in the bundle) to another file and play with the volume level(with the help of framework) during the recording phase?


update: Here's how I'm reading the input file and writing the output. Below code lowers the sound level for "some" of the amplitude values but with lots of noise. Interestingly, if I choose 0.5 as amplitude value it increases the sound level instead of lowering it, but when I use 0.1 as amplitude value it lowers the sound. Both cases involve disturbing noise. I think that's why Art is talking about normalization, but I've no idea about normalization.

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

解决方案

You won't find amplitude scaling operations in (Ext)AudioFile, because it's about the simplest DSP you can do.

Let's assume you use ExtAudioFile to convert whatever you read into 32-bit floats. To change the amplitude, you simply multiply:

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

To increase the gain, you simply use a scale > 1.f. For example, an ampScale of 2.f would give you +6dB of gain.

If you want to normalize, you have to make two passes over the audio: One to determine the sample with the greatest amplitude. Then another to actually apply your computed gain.

Using AudioQueue services just to get access to the volume property is serious, serious overkill.

UPDATE:

In your updated code, you're multiplying each byte by 0.5 instead of each sample. Here's a quick-and-dirty fix for your code, but see my notes below. I wouldn't do what you're doing.

...

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

...

Of course, this isn't the best way to do things: It assumes your file is little-endian 16-bit signed linear PCM. (Most WAV files are, but not AIFF, m4a, mp3, etc.) I'd use the ExtAudioFile API instead of the AudioFile API as this will convert any format you're reading into whatever format you want to work with in code. Usually the simplest thing to do is read your samples in as 32-bit float. Here's an example of your code using ExtAudioAPI to handle any input file format, including 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;

}

这篇关于音频处理:有音量级别播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆