2015-09-18 7 views
10

के लिए ध्वनि शेड्यूल करने के लिए AVAudioEngine का उपयोग करके मैं एक बड़े ऐप के हिस्से के रूप में मेट्रोनोम बना रहा हूं और मेरे पास व्यक्तिगत ध्वनियों के रूप में उपयोग करने के लिए कुछ बहुत छोटी WAV फ़ाइलें हैं I मैं AVAudioEngine का उपयोग करना चाहता हूं क्योंकि एनएसटीमर में महत्वपूर्ण विलंबता समस्याएं हैं और कोर ऑडियो स्विफ्ट में लागू करने के लिए कठिन लग रहा है। मैं निम्नलिखित का प्रयास कर रहा हूं, लेकिन मैं वर्तमान में पहले 3 चरणों को लागू करने में असमर्थ हूं और मैं सोच रहा हूं कि कोई बेहतर तरीका है या नहीं।कम-विलंबता मेट्रोनोम

कोड रूपरेखा:

  1. metronome की वर्तमान सेटिंग (बार प्रति धड़क रहा है और हरा प्रति उप विभाजनों की संख्या; धड़क रहा है के लिए फ़ाइल ए, उप विभाजनों के लिए फ़ाइल बी) के अनुसार फ़ाइल में URL की एक सरणी बनाएँ
  2. प्रोग्राम गति और फ्रेम की लंबाई के आधार पर मौन के उचित संख्या के साथ एक वैव फ़ाइल बनाएं, और प्रत्येक ध्वनि
  3. उन फ़ाइलों को एक ऑडियोबफर या ऑडियोबफर सूची
  4. पर पढ़ें 012,

अब तक मैं, एक भी ध्वनि फ़ाइल की एक पाशन बफर (चरण 4) खेलने के लिए सक्षम किया गया है, लेकिन मैं फ़ाइलों की एक सरणी से एक बफर का निर्माण या प्रोग्राम के रूप में चुप्पी बनाने के लिए नहीं कर पाए हैं और न ही क्या मुझे स्टैक ओवरव्लो पर कोई जवाब मिला है जो इसे संबोधित करता है। तो मैं अनुमान लगा रहा हूं कि यह सबसे अच्छा तरीका नहीं है।

मेरा प्रश्न है: क्या AVAudioEngine का उपयोग करके कम विलंबता के साथ ध्वनियों का अनुक्रम निर्धारित करना संभव है और फिर उस अनुक्रम को लूप करना संभव है? यदि नहीं, स्विफ्ट में कोडिंग करते समय कौन सा ढांचा/दृष्टिकोण शेड्यूलिंग ध्वनियों के लिए सबसे उपयुक्त है?

+0

यह सुनिश्चित नहीं है कि इससे मदद मिलती है, लेकिन कोशिश करें [TheAmazingAudioEngine] (https://github.com/TheAmazingAudioEngine/TheAmazingAudioEngine)। यह उद्देश्य सी में लिखा गया है, लेकिन तेजी से –

+0

में ढांचे के रूप में उपयोग किया जा सकता है मैंने टीएएई को संक्षेप में देखा है और यह सबसे अच्छा विकल्प हो सकता है, हालांकि मुझे उम्मीद है कि एक और मूल दृष्टिकोण है। – blwinters

उत्तर

2

मैं फ़ाइल से ध्वनि युक्त बफर बनाने और आवश्यक लंबाई की चुप्पी बनाने में सक्षम था। उम्मीद है कि यह मदद मिलेगी:

// audioFile here – an instance of AVAudioFile initialized with wav-file 
func tickBuffer(forBpm bpm: Int) -> AVAudioPCMBuffer { 
    audioFile.framePosition = 0 // position in file from where to read, required if you're read several times from one AVAudioFile 
    let periodLength = AVAudioFrameCount(audioFile.processingFormat.sampleRate * 60/Double(bpm)) // tick's length for given bpm (sound length + silence length) 
    let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: periodLength) 
    try! audioFile.readIntoBuffer(buffer) // sorry for forcing try 
    buffer.frameLength = periodLength // key to success. This will append silcence to sound 
    return buffer 
} 

// player – instance of AVAudioPlayerNode within your AVAudioEngine 
func startLoop() { 
    player.stop() 
    let buffer = tickBuffer(forBpm: bpm) 
    player.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil) 
    player.play() 
} 
+0

यह सहायक है, विशेष रूप से मौन के लिए 'बफर.फ्रेम लम्बाई' का उपयोग करके, लेकिन फिर भी प्रत्येक प्रकार की बीट के लिए एक अलग ऑडियो फ़ाइल (यानी डाउनबीट्स के लिए ध्वनि ए, बीट्स के लिए ध्वनि बी, और उपखंडों के लिए ध्वनि सी) की अनुमति नहीं देता है। असली चाल एक बफर बनाने के लिए होगी जिसमें बीट्स और उपविभागों की एक पूरी बार होती है और फिर पूरे बफर/बार को लूप करें। उपर्युक्त उत्तर मूल मेट्रोनोम या क्लिक ट्रैक पर सही है, लेकिन यह "वास्तविक" मेट्रोनोम का समर्थन नहीं कर सकता है जिसके लिए कम से कम दो अलग-अलग ध्वनियों की आवश्यकता होती है। – blwinters

+0

मुझे लगता है कि आप AVAudioPlayerNode (प्रत्येक प्रकार के "टिक" के लिए एक) के साथ ग्राफ बनाने का प्रयास कर सकते हैं। पहला व्यक्ति "मूल" मेट्रोनोम के रूप में खेलते हैं और दूसरा केवल मजबूत धड़कन पर चलता है। – 5hrp

+0

अंत में, यह वह दृष्टिकोण है जिसके साथ मैं गया था और मुझे एक क्लिक पर काम करना पड़ा। भविष्य में, मैं कई नोड्स का प्रयास कर सकता हूं और आवश्यक ऑफ़सेट बनाने के लिए एटटाइम पैरामीटर का उपयोग कर सकता हूं। – blwinters

3

मुझे लगता है कि सबसे कम संभव समय त्रुटि के साथ खेले जाने वाले ध्वनियों के संभावित तरीकों में से एक कॉलबैक के माध्यम से सीधे ऑडियो नमूने प्रदान कर रहा है। आईओएस में आप AudioUnit के साथ ऐसा कर सकते हैं।

इस कॉलबैक में आप नमूना गणना ट्रैक कर सकते हैं और पता कर सकते हैं कि अब आप किस नमूने में हैं। नमूना काउंटर से आप समय मूल्य (नमूना दर का उपयोग करके) जा सकते हैं और मेट्रोनोम जैसे उच्च स्तर के कार्यों के लिए इसका उपयोग कर सकते हैं। यदि आप देखते हैं कि यह मेट्रोनोम ध्वनि चलाने का समय है तो आप उस ध्वनि से ऑडियो नमूने को बफर में कॉपी करना शुरू कर देंगे।

यह किसी भी कोड के बिना एक सैद्धांतिक हिस्सा है, लेकिन आप AudioUnit और कॉलबैक तकनीक के कई उदाहरण पा सकते हैं।

+0

धन्यवाद, मुझे इसे और देखना होगा। – blwinters

2

5hrp के जवाब उनका विस्तार करने के लिए:

सरल मामले ऐसे हैं जिनमें दो की धड़कन, एक उत्साहित (tone1) और एक downbeat (tone2) है ले लो, और आप उनमें से बाहर चाहता हूँ एक दूसरे के साथ चरण ताकि ऑडियो एक निश्चित बीपीएम में (ऊपर, नीचे, ऊपर, नीचे) होगा।

आप (प्रत्येक हरा के लिए एक) AVAudioPlayerNode के दो उदाहरणों की आवश्यकता होगी, उन्हें कॉल audioNode1 और audioNode2

पहली ताल आप चरण में होना चाहता हूँ जाएगा, ताकि सेटअप सामान्य रूप में:

let buffer = tickBuffer(forBpm: bpm) 
audioNode1player.scheduleBuffer(buffer, atTime: nil, options: .loops, completionHandler: nil) 

फिर दूसरी बीट के लिए आप इसे बिल्कुल चरण से बाहर करना चाहते हैं, या टी = बीपीएम/2 पर शुरू करना चाहते हैं। से बाहर

audioNode2player.scheduleBuffer(buffer, atTime: audioTime2, options: .loops, completionHandler: nil) 

यह पाश पर अपने दो धड़कन खेलेंगे, बीपीएम/2:

audioTime2 = AVAudioTime(sampleTime: AVAudioFramePosition(AVAudioFrameCount(audioFile2.processingFormat.sampleRate * 60/Double(bpm) * 0.5)), atRate: Double(1)) 

तुम इतनी तरह बफर में इस चर का उपयोग कर सकते हैं: इस के लिए आप एक AVAudioTime चर का उपयोग कर सकते हैं एक दूसरे से चरण!

यह देखना आसान है कि पूरे बार बनाने के लिए इसे और अधिक धड़कन के लिए कैसे सामान्यीकृत किया जाए। हालांकि यह सबसे सुरुचिपूर्ण समाधान नहीं है, क्योंकि यदि आप 16 वें नोट्स कहना चाहते हैं तो आपको 16 नोड्स बनाना होगा।