2012-09-10 33 views
5

सप्ताहांत में मैंने आईओएस पर ऑडियो संश्लेषण को प्रोग्राम करने का तरीका सीखने के लिए एक ठोकर खाई मार दी। मैं कई वर्षों से आईओएस पर विकास कर रहा हूं, लेकिन मैं सिर्फ ऑडियो संश्लेषण पहलू में जा रहा हूं। अभी, मैं अवधारणाओं को सीखने में मदद करने के लिए सिर्फ डेमो ऐप्स प्रोग्रामिंग कर रहा हूं। मैं वर्तमान में बिना किसी समस्या के ऑडियो इकाइयों के लिए प्लेबैक रेंडरर में साइन लहरों को बनाने और ढेर करने में सक्षम हूं। लेकिन, मैं समझना चाहता हूं कि रेंडरर में क्या हो रहा है, इसलिए मैं प्रत्येक बाएं और दाएं चैनल में 2 अलग साइन लहरों को प्रस्तुत कर सकता हूं। वर्तमान में, मुझे लगता है कि मेरी init ऑडियो अनुभाग में मैं निम्नलिखित परिवर्तन करने की आवश्यकता होगी:आईओएस ऑडियो यूनिट - स्टीरियो साइन वेव्स बनाना

से:

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; 

लेकिन, रेंडरर कुछ हद तक मेरे लिए यूनानी है । मैं किसी भी ट्यूटोरियल या नमूना कोड से काम कर रहा हूं जो मुझे मिल सकता है। मैं चीजों को एक मोनो सिग्नल के दिए गए संदर्भ के लिए काम कर सकता हूं, लेकिन मैं रेंडरर स्टीरियो सिग्नल उत्पन्न नहीं कर सकता। मैं चाहता हूं कि एक बाएं चैनल में एक अलग आवृत्ति और सही चैनल में एक अलग आवृत्ति है - लेकिन मैं ईमानदारी से इसे काम करने के लिए पर्याप्त रेंडरर को समझ नहीं पा रहा हूं। मैंने mbuffers [0] और mbuffers [1] में memcpy फ़ंक्शन का प्रयास किया है, लेकिन यह ऐप को क्रैश करता है। मेरा रेंडर नीचे है (इसमें वर्तमान में स्टैक्ड साइन लहरें हैं, लेकिन स्टीरियो उदाहरण के लिए मैं केवल प्रत्येक चैनल में सेट आवृत्ति की एक लहर का उपयोग कर सकता हूं)।

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

} 

किसी भी मदद के लिए अग्रिम धन्यवाद!

+0

यदि प्रारूप इंटरलीव किया गया है (जैसा कि आपके एएसबीडी सुझाव देता है), तो नमूने बाएं और दाएं वैकल्पिक रूप से एक बफर में होंगे: 'LRLRLRLR'। हालांकि, कॉलबैक में एक इंटरलीवेट प्रारूप होना असामान्य होगा- आम तौर पर प्रारूप ओएस के लिए कैननिकल प्रारूप है। – sbooth

+0

धन्यवाद। मैं वास्तव में बस कुछ ही मिनट पहले यह सब कुछ पता लगाया। जैसा कि आपने कहा था, यह अंतःस्थापित है। मुझे अलग-अलग एल एंड आर चैनलों में साइन लहरों को प्रस्तुत करने के लिए कॉलबैक के माध्यम से लूप कैसे करना है, यह पता लगाना था। फ़िर भी सहायता के लिए धन्यवाद!! – jwkerr

+0

हैलो jwkerr, मैं उम्मीद कर रहा था कि मैं आपको अपने प्रतिपादन समारोह पोस्ट करने में बात कर सकता हूं। मैं थोड़ी देर के लिए काम कर रहे स्टीरियो प्रतिपादन प्राप्त करने की कोशिश कर रहा हूं और इसे काफी प्राप्त नहीं कर सकता। धन्यवाद – VaporwareWolf

उत्तर

3

ओपी ने अपनी समस्या हल कर ली है, लेकिन मैंने सोचा कि एक स्पष्ट उत्तर पोस्ट करना बाकी के लिए सहायक होगा।

मेरे पास टोन को बाएं और दाएं चैनलों को स्वतंत्र रूप से निर्देशित करने के लिए एक ही सवाल था। मैट गैलाघर के अब-मानक An iOS tone generator (an introduction to AudioUnits) के संदर्भ में वर्णन करना सबसे आसान है।

पहले परिवर्तन करने के लिए (@jwkerr निम्नलिखित) createToneUnit विधि में streamFormat.mChannelsPerFrame = 2; (streamFormat.mChannelsPerFrame = 1; के बजाय) स्थापित करने के लिए है। एक बार यह हो जाता है और आप दो चैनलों/प्रत्येक फ्रेम में बफर है, तो आप 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; 
} 

पाठ्यक्रम channelLR[2] का एक bool सरणी जिसका तत्वों आप चाहे इंगित करने के लिए सेट किया गया है संबंधित चैनल श्रव्य है। ध्यान दें कि कार्यक्रम को चुप चैनलों के फ्रेम को शून्य पर स्पष्ट रूप से सेट करने की आवश्यकता है, अन्यथा आपको कुछ मजाकिया स्वर मिलते हैं।

+0

चैनलएलआर को और अधिक समझाने की जरूरत है। –

+0

संपादित। क्या यह सहायक है? – JohnK

+0

जब आप चैनलएलआर सेट करते हैं? मैंने आपके उदाहरण की कोशिश की है लेकिन यह स्थिर –