2012-09-10 38 views
5

Cuối tuần qua, tôi đã gặp phải một trở ngại khi học cách lập trình tổng hợp âm thanh trên iOS. Tôi đã và đang phát triển trên iOS trong nhiều năm, nhưng tôi chỉ đi vào khía cạnh tổng hợp âm thanh. Ngay bây giờ, tôi chỉ là lập trình ứng dụng demo để giúp tôi tìm hiểu các khái niệm. Tôi hiện đã có thể xây dựng và ngăn xếp sóng sin trong trình phát lại cho các Đơn vị Âm thanh mà không gặp sự cố. Nhưng, tôi muốn hiểu những gì đang xảy ra trong trình kết xuất để tôi có thể hiển thị 2 sóng sin riêng biệt trong mỗi Kênh Trái và Phải. Hiện nay, tôi cho rằng trong phần âm thanh init của tôi, tôi sẽ cần phải thực hiện những thay đổi sau:Đơn vị âm thanh iOS - Tạo sóng Sine Stereo

Từ:

AudioStreamBasicDescription audioFormat; 
    audioFormat.mSampleRate = kSampleRate; 
    audioFormat.mFormatID = kAudioFormatLinearPCM; 
    audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
    audioFormat.mFramesPerPacket = 1; 
    audioFormat.mChannelsPerFrame = 1; 
    audioFormat.mBitsPerChannel = 16; 
    audioFormat.mBytesPerPacket = 2; 
    audioFormat.mBytesPerFrame = 2; 

Để:

AudioStreamBasicDescription audioFormat; 
    audioFormat.mSampleRate = kSampleRate; 
    audioFormat.mFormatID = kAudioFormatLinearPCM; 
    audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
    audioFormat.mFramesPerPacket = 1; 
    audioFormat.mChannelsPerFrame = 2; 
    audioFormat.mBitsPerChannel = 16; 
    audioFormat.mBytesPerPacket = 4; 
    audioFormat.mBytesPerFrame = 4; 

Nhưng, các renderer là hơi greek với tôi . Tôi đã được làm việc tắt của bất kỳ hướng dẫn hoặc mã mẫu tôi có thể tìm thấy. Tôi có thể làm cho mọi thứ hoạt động trong ngữ cảnh của tín hiệu mono, nhưng tôi không thể làm cho trình kết xuất tạo tín hiệu âm thanh nổi. Tất cả những gì tôi muốn là một tần số riêng biệt trong kênh bên trái và tần số khác nhau trong kênh phù hợp - nhưng tôi thành thật không hiểu trình kết xuất đủ để làm cho nó hoạt động. Tôi đã thử các chức năng memcpy vào mBuffers [0] và mbuffers [1], nhưng điều đó làm hỏng ứng dụng. Render của tôi là dưới đây (nó hiện đang chứa sóng sin xếp chồng lên nhau, nhưng đối với các ví dụ stereo tôi chỉ có thể sử dụng một làn sóng của một tần số thiết lập trong mỗi kênh mặc dù).

#define kOutputBus 0 
#define kSampleRate 44100 
//44100.0f 
#define kWaveform (M_PI * 2.0f/kSampleRate) 

OSStatus playbackCallback(void *inRefCon, 
          AudioUnitRenderActionFlags *ioActionFlags, 
          const AudioTimeStamp *inTimeStamp, 
          UInt32 inBusNumber, 
          UInt32 inNumberFrames, 
          AudioBufferList *ioData) { 

     HomeViewController *me = (HomeViewController *)inRefCon; 

    static int phase = 1; 
    static int phase1 = 1; 

    for(UInt32 i = 0; i < ioData->mNumberBuffers; i++) { 

     int samples = ioData->mBuffers[i].mDataByteSize/sizeof(SInt16); 

     SInt16 values[samples]; 

     float waves; 
     float volume=.5; 
     float wave1; 

     for(int j = 0; j < samples; j++) { 


      waves = 0; 
      wave1 = 0; 

      MyManager *sharedManager = [MyManager sharedManager]; 


      wave1 = sin(kWaveform * sharedManager.globalFr1 * phase1)*sharedManager.globalVol1; 
      if (0.000001f > wave1) { 
       [me setFr1:sharedManager.globalFr1]; 
       phase1 = 0; 
       //NSLog(@"switch"); 
      } 

      waves += wave1; 
      waves += sin(kWaveform * sharedManager.globalFr2 * phase)*sharedManager.globalVol2; 
      waves += sin(kWaveform * sharedManager.globalFr3 * phase)*sharedManager.globalVol3; 
      waves += sin(kWaveform * sharedManager.globalFr4 * phase)*sharedManager.globalVol4; 
      waves += sin(kWaveform * sharedManager.globalFr5 * phase)*sharedManager.globalVol5; 
      waves += sin(kWaveform * sharedManager.globalFr6 * phase)*sharedManager.globalVol6; 
      waves += sin(kWaveform * sharedManager.globalFr7 * phase)*sharedManager.globalVol7; 
      waves += sin(kWaveform * sharedManager.globalFr8 * phase)*sharedManager.globalVol8; 
      waves += sin(kWaveform * sharedManager.globalFr9 * phase)*sharedManager.globalVol9; 
      waves *= 32767/9; // <--------- make sure to divide by how many waves you're stacking 

      values[j] = (SInt16)waves; 
      values[j] += values[j]<<16; 

      phase++; 
      phase1++; 

     } 

     memcpy(ioData->mBuffers[i].mData, values, samples * sizeof(SInt16)); 

    } 


    return noErr; 

} 

Cảm ơn bạn đã giúp đỡ!

+0

Nếu định dạng được đan xen (như ASBD của bạn gợi ý), thì các mẫu sẽ nằm trong một vùng đệm xen kẽ sang trái và phải: 'LRLRLRLR'. Tuy nhiên, sẽ không bình thường nếu có định dạng xen kẽ trong một cuộc gọi lại - thường là định dạng là định dạng chuẩn cho hệ điều hành. – sbooth

+0

Cảm ơn. Tôi thực sự chỉ tìm ra tất cả chỉ trong vài phút trước. Nó được xen kẽ như bạn nói, mặc dù. Tôi đã phải tìm ra cách lặp qua gọi lại để hiển thị các sóng sin trong các kênh L & R riêng biệt. Cảm ơn sự giúp đỡ của bạn!! – jwkerr

+0

Xin chào jwkerr, tôi đã hy vọng rằng tôi có thể nói chuyện với bạn về việc đăng chức năng dựng hình của bạn. Tôi đã cố gắng để có được rendering stereo làm việc một lúc và không thể nhận được nó. Cảm ơn – VaporwareWolf

Trả lời

3

OP dường như đã giải quyết được vấn đề của anh ấy, nhưng tôi nghĩ rằng việc đăng câu trả lời rõ ràng sẽ hữu ích cho tất cả chúng ta.

Tôi có cùng một câu hỏi muốn hướng các âm sang kênh trái và phải một cách độc lập. Đó là cách dễ nhất để mô tả về tiêu chuẩn hiện tại của Matt Gallagher An iOS tone generator (an introduction to AudioUnits).

Thay đổi đầu tiên cần thực hiện là đặt (sau @jwkerr) streamFormat.mChannelsPerFrame = 2; (thay vì streamFormat.mChannelsPerFrame = 1;) theo phương thức createToneUnit. Khi đã xong và bạn có hai kênh/bộ đệm trong mỗi khung hình, bạn cần phải điền vào bộ đệm trái và phải một cách độc lập trong RenderTone():

// Set the left and right buffers independently 
Float32 tmp; 
Float32 *buffer0 = (Float32 *)ioData->mBuffers[0].mData; 
Float32 *buffer1 = (Float32 *)ioData->mBuffers[1].mData; 

// Generate the samples 
for (UInt32 frame = 0; frame < inNumberFrames; frame++) { 
    tmp = sin(theta) * amplitude; 

    if (channelLR[0]) buffer0[frame] = tmp; else buffer0[frame] = 0; 
    if (channelLR[1]) buffer1[frame] = tmp; else buffer1[frame] = 0; 

    theta += theta_increment; 
    if (theta > 2.0 * M_PI) theta -= 2.0 * M_PI; 
} 

Tất nhiên channelLR[2] là một mảng bool có yếu tố mà bạn thiết lập để cho biết các kênh tương ứng có thể nghe được. Lưu ý rằng chương trình cần đặt rõ ràng các khung của kênh im lặng về 0, nếu không bạn sẽ nhận được một số âm thanh vui nhộn.

+0

channelLR cần giải thích thêm. –

+0

Đã chỉnh sửa. Điều đó có hữu ích không? – JohnK

+0

khi nào bạn đặt channelLR? Tôi đã thử ví dụ của bạn nhưng nó tĩnh –

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