2012-04-15 15 views
8

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

मैं जो करने की कोशिश कर रहा हूं: मैं एक साधारण एंड्रॉइड ऑडियो सिंथेसाइज़र बना रहा हूं। अभी, मैं वास्तविक समय में एक साइन-टोन खेल रहा हूं, यूआई में एक स्लाइडर के साथ जो टोन की आवृत्ति को बदलता है क्योंकि उपयोगकर्ता इसे समायोजित करता है।

मैंने इसे कैसे बनाया है: असल में, मेरे पास दो धागे हैं - एक कार्यकर्ता थ्रेड और आउटपुट थ्रेड। कार्यकर्ता थ्रेड बस हर बार अपनी टिक() विधि कहलाता है, साइन लहर डेटा के साथ एक बफर भरता है। एक बार बफर भरने के बाद, यह आउटपुट थ्रेड को अलर्ट करता है कि डेटा ऑडियो ट्रैक पर लिखा जाने के लिए तैयार है। कारण मैं दो धागे का उपयोग कर रहा हूं क्योंकि audiotrack.write() ब्लॉक है, और मैं चाहता हूं कि कार्यकर्ता थ्रेड जितनी जल्दी हो सके डेटा को संसाधित करना शुरू कर सके (ऑडियो ट्रैक को लिखने के लिए प्रतीक्षा करने के बजाय)। यूआई पर स्लाइडर बस कार्यकर्ता धागे में एक चर बदलता है, ताकि आवृत्ति (स्लाइडर के माध्यम से) में कोई भी परिवर्तन कार्यकर्ता थ्रेड की टिक() विधि द्वारा पढ़ा जाएगा।

क्या काम करता है: लगभग सबकुछ; धागे अच्छी तरह से संवाद करते हैं, प्लेबैक में कोई अंतराल या क्लिक नहीं लगता है। बड़े बफर आकार (धन्यवाद एंड्रॉइड) के बावजूद, प्रतिक्रिया ठीक है। फ्रीक्वेंसी वैरिएबल बदलता है, जैसे कि टिक() विधि में बफर गणनाओं के दौरान उपयोग किए जाने वाले इंटरमीडिएट मान (Log.i() द्वारा सत्यापित)।

क्या काम नहीं करता है: किसी कारण से, मुझे श्रव्य आवृत्ति में निरंतर परिवर्तन नहीं दिख रहा है। जब मैं स्लाइडर को समायोजित करता हूं, तो आवृत्ति चौड़ाई या चौथाई जितनी चौड़ी होती है। सैद्धांतिक रूप से, मुझे 1 हर्ट्ज के रूप में मिनटों में परिवर्तन सुनना चाहिए, लेकिन मैं नहीं हूं। विचित्र रूप से पर्याप्त, ऐसा लगता है जैसे स्लाइडर में परिवर्तन हार्मोनिक श्रृंखला में अंतराल के माध्यम से साइन लहर उत्पन्न कर रहा है; हालांकि, मैं सत्यापित कर सकता हूं कि आवृत्ति चर डिफ़ॉल्ट आवृत्ति के अभिन्न गुणों पर स्नैप नहीं कर रहा है।

मेरे ऑडियो ट्रैक में इस तरह के रूप में सेट है:

_buffSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); 
_audioTrackOut = new AudioTrack(AudioManager.STREAM_MUSIC, _sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, _buffSize, AudioTrack.MODE_STREAM); 

कार्यकर्ता धागा के बफर डाला जा रहा है (टिक के माध्यम से()) जैसे:

public short[] tick() 
{ 
    short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes)/2 
    for (int i = 0; i < _outBuffSize/2; i++) 
    { 
     outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle))); 

     //Update angleIncrement, as the frequency may have changed by now 
     _angleIncrement = (float) (2.0f * Math.PI) * _freq/_sampleRate; 
     _currentAngle = _currentAngle + _angleIncrement;  
    } 
    return outBuff;  
} 

ऑडियो डेटा की तरह लिखा जा रहा है यह:

_audioTrackOut.write(fromWorker, 0, fromWorker.length); 

किसी भी मदद की सराहना की जाएगी। मैं आवृत्ति में अधिक क्रमिक परिवर्तन कैसे प्राप्त कर सकता हूं? मुझे पूरा भरोसा है कि टिक() में मेरा तर्क ध्वनि है, क्योंकि Log.i() सत्यापित करता है कि वेरिएबल्स कोण इंस्ट्रक्शन और वर्तमान एंगल को ठीक से अपडेट किया जा रहा है।

धन्यवाद!

अद्यतन:

मैं एक ऐसी ही समस्या पाई गई: Android AudioTrack buffering problems समाधान का प्रस्ताव है कि एक audiotrack, जो समझ में आता है के लिए काफी तेजी से नमूने का उत्पादन करने में सक्षम होना चाहिए। मैंने अपनी नमूना दर 22050 हर्ट्ज तक घटा दी, और कुछ अनुभवजन्य परीक्षण चलाए - मैं अपने बफर (टिक() के माध्यम से) को सबसे खराब मामले में लगभग 6ms में भर सकता हूं। यह पर्याप्त से अधिक है। 22050 हर्ट्ज पर, ऑडियोट्रैक मुझे 2048 नमूने (या 40 9 6 बाइट्स) का बफर आकार देता है। तो, प्रत्येक भरे बफर ~ 0 के लिए रहता है।ऑडियो के 0928 सेकेंड, जो डेटा (1 ~ 6 एमएस) बनाने के लिए काफी लंबा है। तो, मुझे पता है कि मुझे पर्याप्त तेजी से नमूनों का उत्पादन करने में कोई समस्या नहीं है।

मुझे यह भी ध्यान रखना चाहिए कि एप्लिकेशन लाइफसाइकिल के पहले 3 सेकंड के लिए, यह ठीक काम करता है - स्लाइडर की एक चिकनी स्वीप ऑडियो आउटपुट में एक चिकनी स्वीप उत्पन्न करती है। इसके बाद, यह वास्तव में चंचल हो जाता है (ध्वनि केवल 100 एमएचजेड के बारे में बदलता है), और उसके बाद, यह स्लाइडर इनपुट का जवाब देना बंद कर देता है।

मैंने एक बग भी तय किया, लेकिन मुझे नहीं लगता कि इसका प्रभाव है। AudioTrack.getMinBufferSize() BYTES में सबसे छोटा स्वीकार्य बफर आकार देता है, और मैं इस नंबर का उपयोग टिक() में बफर की लंबाई के रूप में कर रहा था - अब मैं आधे नंबर (प्रति नमूना 2 बाइट्स) का उपयोग करता हूं।

+0

'_freq' बदलने के लिए आप किस घटना का उपयोग करते हैं? क्या यह वास्तव में हर बार 1 हर्ट्ज में बदल जाता है? क्षमा करें, मैं आपकी ** स्पष्ट रूप से समझ नहीं पा रहा हूं ** क्या काम नहीं करता ** अनुभाग। क्या आप ** अपनी समस्या ** सुनना संभव बनाने के लिए एक पूर्ण कार्य कोड नमूना या संश्लेषित ध्वनि खंड प्रदान कर सकते हैं। ध्वनि खंड के लिए: कच्चे ध्वनि डेटा प्रारूप ठीक है - बस अपने बफर को फ़ाइल में लिखें, न कि ऑडियो कार्ड पर। उदाहरण के लिए, 16 बिट/हस्ताक्षरित/मोनो/44100 हर्ट्ज। –

+0

_freq को बदलने के लिए, मैं एक ऑनसेकबार चेंजलिस्टर का उपयोग कर रहा हूं जो _freq पर प्रोग्रेस चेंज() के माध्यम से एक नया int मान लिखता है। हालांकि, मैंने बटन (ऊपर/नीचे) का उपयोग करने का भी प्रयास किया है जो आवृत्ति को 1 हर्ट्ज तक बढ़ाता है, और कई लोगों के बाद पिच में केवल एक श्रव्य अंतर होता है (जैसे कि ध्वनि लगभग 3 या 4 वें तक पिच में कूदता है 1 हर्ट्ज की बजाय)। क्या हो रहा है इसका एक उदाहरण यहां दिया गया है; यह वही है जो मैं धीरे-धीरे स्लाइडर को ऊपर और नीचे स्लाइड करता हूं, आवृत्ति को 1 हर्ट्ज की वृद्धि में बढ़ाता हूं। (~ 200 - ~ 1000 हर्ट्ज से): http://www.sendspace.com/file/tpxuwr – Tsherr

+0

मुझे ऑनलाइन एक समान समस्या मिली, लेकिन इसके प्रस्तावित समाधान ने मदद नहीं की - ऊपर दिए गए अपडेट को देखें। – Tsherr

उत्तर

4

मुझे यह मिल गया है!

यह पता चला है कि समस्या में बफर या थ्रेडिंग के साथ कुछ लेना देना नहीं है।

यह पहले कुछ सेकंड में ठीक लगता है, क्योंकि गणना का कोण अपेक्षाकृत छोटा है। जैसे-जैसे प्रोग्राम चलता है और कोण बढ़ता है, Math.sin (_currentAngle) अविश्वसनीय मानों का उत्पादन शुरू करता है।

तो, मैंने Math.sin() को FloatMath.sin() के साथ बदल दिया।

मैं भी _currentAngle = _currentAngle + _angleIncrement;

प्रतिस्थापित

_currentAngle = ((_currentAngle + _angleIncrement) % (2.0f * (float) Math.PI)); साथ है, तो कोण हमेशा < 2 * पीआई है।

एक आकर्षण की तरह काम करता है! आपकी मदद के लिए बहुत बहुत धन्यवाद, प्राइमोरियन droid!

+0

अरे, मैं लगभग 2 * पीआई सामान्यीकरण भूल गया! मैंने इसे अपने पुराने कोड में देखा है, लेकिन आपकी अनुपस्थिति में तुम्हारी अनुपस्थिति है। लेकिन मैंने सोचा कि कोण चर के ओवरफ्लो को क्लिक का प्रभाव देना चाहिए और आपका नमूना अलग लगता है। वैसे भी, मुझे खुशी है कि आपने अपनी समस्या हल की है। –

संबंधित मुद्दे