2010-10-20 55 views
8

Tôi muốn đọc tệp âm thanh từ gói ứng dụng, sao chép, phát với mức âm lượng tối đa (Giá trị tăng hoặc công suất cực đại, tôi không chắc chắn về tên kỹ thuật của nó), và sau đó viết lại nó thành một tệp khác cho nhóm.Xử lý âm thanh: Chơi với mức âm lượng

Tôi đã sao chép và viết một phần. Tệp kết quả giống với tệp đầu vào. Tôi sử dụng các hàm AudioFileReadBytes() và AudioFileWriteBytes() của các dịch vụ AudioFile trong khung công cụ AudioToolbox để thực hiện điều đó.

Vì vậy, tôi có byte của tệp đầu vào và định dạng dữ liệu âm thanh của nó (thông qua sử dụng AudioFileGetProperty() với kAudioFilePropertyDataFormat) nhưng tôi không thể tìm thấy biến này để phát với mức âm lượng tối đa của tệp gốc.

Để làm rõ mục đích của mình, tôi đang cố gắng tạo một tệp âm thanh khác có mức âm lượng tăng hoặc giảm tương ứng với mức âm lượng gốc, vì vậy tôi không quan tâm đến mức âm lượng của hệ thống do người dùng đặt hoặc iOS.

Có thể thực hiện với khuôn khổ mà tôi đã đề cập không? Nếu không, có đề xuất thay thế nào không?

Cảm ơn


chỉnh sửa: Đi bộ qua câu trả lời của Sam về một số vấn đề cơ bản audio, tôi quyết định mở rộng câu hỏi với thay thế khác.

Tôi có thể sử dụng dịch vụ AudioQueue để ghi tệp âm thanh hiện có (trong gói) vào một tệp khác và phát với mức âm lượng (với sự trợ giúp của khung công tác) trong giai đoạn ghi không?


cập nhật: Đây là cách tôi đọc tệp đầu vào và viết đầu ra. Mã dưới đây làm giảm mức âm thanh cho "một số" của các giá trị biên độ nhưng với rất nhiều tiếng ồn. Thật thú vị, nếu tôi chọn 0,5 là giá trị biên độ nó làm tăng mức âm thanh thay vì giảm nó, nhưng khi tôi sử dụng 0,1 như giá trị biên độ nó làm giảm âm thanh. Cả hai trường hợp liên quan đến tiếng ồn đáng lo ngại. Tôi nghĩ đó là lý do tại sao Art đang nói về bình thường hóa, nhưng tôi không có ý tưởng về việc bình thường hóa.

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

Trả lời

13

Bạn sẽ không tìm thấy hoạt động chia tỷ lệ biên độ trong (Ext) AudioFile, vì đó là về DSP đơn giản nhất mà bạn có thể thực hiện.

Giả sử bạn sử dụng ExtAudioFile để chuyển đổi bất kỳ thứ gì bạn đã đọc thành phao 32 bit.Để thay đổi biên độ, bạn chỉ cần nhân lên:

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

Để tăng lợi ích, bạn chỉ cần sử dụng thang tỷ lệ> 1.f. Ví dụ, một ampScale của 2.f sẽ cho bạn + 6dB tăng.

Nếu bạn muốn bình thường hóa, bạn phải thực hiện hai lần truyền âm thanh: Một để xác định mẫu có biên độ lớn nhất. Sau đó, người khác thực sự áp dụng mức tăng tính toán của bạn.

Sử dụng dịch vụ AudioQueue chỉ để truy cập vào thuộc tính âm lượng là mức độ nghiêm trọng, quá mức nghiêm trọng.

UPDATE:

Trong mã cập nhật của bạn, bạn đang nhân mỗi byte 0,5 thay vì mỗi mẫu. Dưới đây là bản sửa lỗi nhanh chóng và bẩn cho mã của bạn, nhưng xem ghi chú của tôi bên dưới. Tôi sẽ không làm những gì bạn đang làm.

... 

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

... 

Tất nhiên, đây không phải là cách tốt nhất để làm việc: Giả sử tệp của bạn là PCM tuyến tính 16 bit có ký kết ít. (Hầu hết các tệp WAV, nhưng không phải AIFF, m4a, mp3, v.v.) Tôi muốn sử dụng API ExtAudioFile thay vì API AudioFile vì điều này sẽ chuyển đổi mọi định dạng bạn đang đọc thành bất kỳ định dạng nào bạn muốn làm việc với mã. Thông thường, điều đơn giản nhất là đọc các mẫu của bạn dưới dạng phao 32 bit. Dưới đây là một ví dụ về mã của bạn sử dụng ExtAudioAPI để xử lý bất kỳ định dạng tập tin đầu vào, kể cả 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

Cảm ơn Nghệ thuật, tôi đã cập nhật cả mã và câu hỏi của tôi theo đề xuất của bạn, nhưng điều này gây ra các vấn đề khác. Có lẽ tôi đã sai, nhưng nó sẽ hoàn hảo nếu bạn có thể nhìn vào câu hỏi được cập nhật với đoạn mã. – cocoatoucher

+0

Tôi đã chỉnh sửa câu trả lời của mình với giải thích tại sao mã của bạn không hoạt động và ví dụ về mã sẽ. –

+0

Nghệ thuật, tôi rất biết ơn câu trả lời này. Bạn không chỉ cung cấp cho tôi mã mà còn giúp tôi hiểu những gì đang xảy ra. Cảm ơn rất nhiều! Hãy tiếp tục chia sẻ. Nhờ những người khác nữa. – cocoatoucher

0

Đối với hầu hết các định dạng tệp âm thanh phổ biến không có một biến khối lượng chính. Thay vào đó, bạn sẽ cần phải lấy (hoặc chuyển đổi thành) mẫu âm thanh PCM và thực hiện ít nhất một số xử lý tín hiệu số tối thiểu (nhân, bão hòa/giới hạn/AGC, định hình nhiễu định lượng và vv) trên mỗi mẫu.

+0

đó là tin xấu :) Tôi muốn khuôn khổ xử lý các hoạt động khoa học như vậy nếu cần :) – cocoatoucher

0

Nếu tệp âm thanh được chuẩn hóa, bạn không thể làm gì để làm cho tệp lớn hơn. Ngoại trừ trường hợp âm thanh được mã hóa kém, âm lượng gần như hoàn toàn là cõi của công cụ phát lại.

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

tập tin âm thanh được lưu trữ đúng cách sẽ có khối lượng đỉnh tại hoặc gần giá trị lớn nhất có sẵn cho chiều sâu bit của file. Nếu bạn cố gắng 'giảm âm lượng' của một tệp âm thanh, về cơ bản bạn sẽ chỉ làm giảm chất lượng âm thanh.

+0

Cảm ơn, điều đó có ý nghĩa. Sau đó, tôi phải mở rộng câu hỏi và chia sẻ các lựa chọn thay thế của riêng mình. – cocoatoucher

1

Tôi nghĩ rằng bạn nên tránh làm việc với 8 bit ký tự unsigned cho âm thanh, nếu bạn có thể. Cố gắng lấy dữ liệu dưới dạng 16 bit hoặc 32 bit, điều này sẽ tránh được một số vấn đề về chất lượng âm thanh/nhiễu.

+0

Cảm ơn, tôi đã thử với Float32 nhưng tôi vẫn có tiếng ồn tương tự – cocoatoucher

Các vấn đề liên quan