2010-10-06 13 views
5

का उपयोग कर रहा System.Speech.Synthesis.SpeechSynthesizer उपयोग कर रहा हूँ पाठ से वाक् कन्वर्ट करने के लिए SpeechAudioFormatInfo साथ स्ट्रीम करने के लिए। और माइक्रोसॉफ्ट के एनीमिक दस्तावेज के कारण (मेरा लिंक देखें, कोई टिप्पणी या कोड उदाहरण नहीं हैं) मुझे दो तरीकों के बीच अंतर के सिर या पूंछ बनाने में परेशानी हो रही है:टीटीएस SpeechSynthesizer

SetOutputToAudioStream और SetOutputToWaveStream।

यहाँ मैं क्या निष्कर्ष निकाला है

SetOutputToAudioStream एक धारा और एक SpeechAudioFormatInfo आवृत्ति लहर फ़ाइल के स्वरूप को परिभाषित करता है (प्रति सेकंड के नमूने, बिट्स प्रति सेकंड, ऑडियो चैनलों, आदि) और के लिए पाठ लिखते हैं लेता है धारा।

SetOutputToWaveStream सिर्फ एक धारा लेता है और धारा करने के लिए एक 16 बिट, मोनो, 22kHz, पीसीएम लहर फ़ाइल लिखता है। SpeechAudioFormatInfo में पास करने का कोई तरीका नहीं है।

मेरे समस्या SetOutputToAudioStream धारा के लिए एक वैध लहर फ़ाइल में लिखने नहीं करता है। उदाहरण के लिए मुझे System.Media.SoundPlayer पर स्ट्रीम पास करते समय एक अवैधऑपरेशन अपवाद ("लहर शीर्षलेख भ्रष्ट है") मिलता है। अगर मैं डिस्क पर स्ट्रीम लिखता हूं और इसे डब्लूएमपी के साथ खेलने का प्रयास करता हूं तो मुझे "विंडोज मीडिया प्लेयर फ़ाइल नहीं चला सकता ..." त्रुटि मिलती है लेकिन SetOutputToWaveStream द्वारा लिखी गई स्ट्रीम दोनों में ठीक से खेलती है। मेरा सिद्धांत यह है कि SetOutputToAudioStream एक (वैध) शीर्षलेख नहीं लिख रहा है।

अजीब SetOutputTo के लिए नामकरण सम्मेलनों * ब्ला * असंगत है। SetOutputToWaveFile एक SpeechAudioFormatInfo लेता है जबकि SetOutputToWaveStream नहीं करता है।

मैं एक 8kHz, 16 बिट, एक धारा को मोनो लहर फ़ाइल, कुछ है कि न तो SetOutputToAudioStream या SetOutputToWaveStream मुझे ऐसा करने की अनुमति लिखने में सक्षम होना चाहिए। क्या किसी के पास स्पीचसिंथेसाइज़र और इन दो तरीकों में अंतर्दृष्टि है?

Stream ret = new MemoryStream(); 
using (SpeechSynthesizer synth = new SpeechSynthesizer()) 
{ 
    synth.SelectVoice(voiceName); 
    synth.SetOutputToWaveStream(ret); 
    //synth.SetOutputToAudioStream(ret, new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono)); 
    synth.Speak(textToSpeak); 
} 

समाधान::

Stream ret = new MemoryStream(); 
using (SpeechSynthesizer synth = new SpeechSynthesizer()) 
{ 
    var mi = synth.GetType().GetMethod("SetOutputStream", BindingFlags.Instance | BindingFlags.NonPublic); 
    var fmt = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Sixteen, AudioChannel.Mono); 
    mi.Invoke(synth, new object[] { ret, fmt, true, true }); 
    synth.SelectVoice(voiceName); 
    synth.Speak(textToSpeak); 
} 
return ret; 

:

@Hans Passant को बहुत धन्यवाद, यहाँ अब मैं क्या उपयोग कर रहा हूँ का सार है

संदर्भ के लिए, यहाँ कुछ कोड है मेरे किसी न किसी परीक्षण के लिए यह बहुत अच्छा काम करता है, हालांकि प्रतिबिंब का उपयोग करना थोड़ा मुश्किल है, यह फ़ाइल को डिस्क पर लिखने और स्ट्रीम खोलने से बेहतर है।

उत्तर

6

आपका कोड स्निपेट बोर्क किया गया है, आप synth का निपटान करने के बाद उपयोग कर रहे हैं। लेकिन यह सच समस्या नहीं है मुझे यकीन है। SetOutputToAudioStream कच्चे पीसीएम ऑडियो, 'संख्या' का उत्पादन करता है। एक कंटेनर फ़ाइल प्रारूप (हेडर) के बिना .wav फ़ाइल में क्या उपयोग किया जाता है। हां, जिसे नियमित मीडिया कार्यक्रम के साथ वापस नहीं खेला जा सकता है।

SetOutputToWaveStream के लिए अनुपलब्ध ओवरलोड जो SpeechAudioFormatInfo लेता है अजीब है। यह वास्तव में मेरे लिए एक निरीक्षण की तरह दिखता है, भले ही यह .NET ढांचे में बेहद दुर्लभ है। कोई अनिवार्य कारण नहीं है कि इसे क्यों काम नहीं करना चाहिए, अंतर्निहित एसएपीआई इंटरफ़ेस इसका समर्थन करता है। इसे निजी SetOutputStream विधि को कॉल करने के लिए प्रतिबिंब के साथ चारों ओर हैक किया जा सकता है। इस ठीक काम किया जब मैं यह परीक्षण किया है, लेकिन मैं यह पुष्टि नहीं कर सकते:

using System.Reflection; 
... 
      using (Stream ret = new MemoryStream()) 
      using (SpeechSynthesizer synth = new SpeechSynthesizer()) { 
       var mi = synth.GetType().GetMethod("SetOutputStream", BindingFlags.Instance | BindingFlags.NonPublic); 
       var fmt = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Eight, AudioChannel.Mono); 
       mi.Invoke(synth, new object[] { ret, fmt, true, true }); 
       synth.Speak("Greetings from stack overflow"); 
       // Testing code: 
       using (var fs = new FileStream(@"c:\temp\test.wav", FileMode.Create, FileAccess.Write, FileShare.None)) { 
        ret.Position = 0; 
        byte[] buffer = new byte[4096]; 
        for (;;) { 
         int len = ret.Read(buffer, 0, buffer.Length); 
         if (len == 0) break; 
         fs.Write(buffer, 0, len); 
        } 
       } 
      } 

आप हैक के साथ असहज हैं, तो Path.GetTempFileName का उपयोग कर() अस्थायी तौर पर एक फ़ाइल निश्चित रूप से काम करेंगे करने के लिए यह स्ट्रीम करने के लिए है।

+0

इसके बारे में सोचने के लिए आओ, आखिरी तर्क शायद गलत होना चाहिए, इसलिए यह स्ट्रीम को बंद नहीं करता है। यद्यपि मेमोरीस्ट्रीम के लिए कोई फर्क नहीं पड़ता। –

+0

आप सही हैं, synth.Speak() मेरे कोड में उपयोग के अंदर था। मैंने कोड स्निपेट संपादित किया है। मैं आपका कोड एक शॉट दूंगा, ऐसा लगता है कि यह जो मैं पूछ रहा हूं उसे पूरा करेगा। मैं मानता हूं कि यह एक निरीक्षण की तरह दिखता है। धन्यवाद! – AceJordin