Example #1
0
 def _processQueue(self):
     if not self._queuedSpeech and self._player is None:
         # If oneCore speech has not been successful yet the player will not have initialised. (#11544)
         # We can't sync the player in this instance.
         log.debugWarning(
             "Cannot process speech queue as player not set and no speech queued"
         )
         return
     if not self._queuedSpeech:
         # There are no more queued utterances at this point, so call sync.
         # This blocks while waiting for the final chunk to play,
         # so by the time this is done, there might be something queued.
         # #10721: We use sync instead of idle because idle closes the audio
         # device. If there's something in the queue after playing the final chunk,
         # that will result in WaveOutOpen being called in the callback when we
         # push the next chunk of audio. We *really* don't want this because calling
         # WaveOutOpen blocks for ~100 ms if called from the callback when the SSML
         # includes marks, resulting in lag between utterances.
         if isDebugForSynthDriver():
             log.debug("Calling sync on audio player")
         self._player.sync()
     if not self._queuedSpeech:
         # There's still nothing in the queue, so it's okay to call idle now.
         if isDebugForSynthDriver():
             log.debug("Calling idle on audio player")
         self._player.idle()
         synthDoneSpeaking.notify(synth=self)
     while self._queuedSpeech:
         item = self._queuedSpeech.pop(0)
         if isinstance(item, tuple):
             # Parameter change.
             # Note that, if prosody otions aren't supported, this code will never be executed.
             func, value = item
             value = ctypes.c_double(value)
             func(self._ocSpeechToken, value)
             continue
         self._wasCancelled = False
         if isDebugForSynthDriver():
             log.debug("Begin processing speech")
         self._isProcessing = True
         # ocSpeech_speak is async.
         # It will call _callback in a background thread once done,
         # which will eventually process the queue again.
         self._dll.ocSpeech_speak(self._ocSpeechToken, item)
         return
     if isDebugForSynthDriver():
         log.debug("Queue empty, done processing")
     self._isProcessing = False
Example #2
0
    def _callback(self, bytes, len, markers):
        if self._earlyExitCB:
            # prevent any pending callbacks from interacting further with the synth.
            # used during termination.
            return
        if len == 0:
            # Speech failed
            self._handleSpeechFailure()
            return
        else:
            self._consecutiveSpeechFailures = 0
        # This gets called in a background thread.
        stream = io.BytesIO(ctypes.string_at(bytes, len))
        wav = wave.open(stream, "r")
        self._maybeInitPlayer(wav)
        data = wav.readframes(wav.getnframes())
        if markers:
            markers = markers.split('|')
        else:
            markers = []
        prevPos = 0

        # Push audio up to each marker so we can sync the audio with the markers.
        for marker in markers:
            if self._wasCancelled:
                break
            name, pos = marker.split(':')
            index = int(name)
            pos = int(pos)
            # pos is a time offset in 100-nanosecond units.
            # Convert this to a byte offset.
            # Order the equation so we don't have to do floating point.
            pos = pos * self._bytesPerSec // HUNDRED_NS_PER_SEC
            # Push audio up to this marker.
            self._player.feed(data[prevPos:pos],
                              onDone=lambda index=index: synthIndexReached.
                              notify(synth=self, index=index))
            prevPos = pos
        if self._wasCancelled:
            if isDebugForSynthDriver():
                log.debug("Cancelled, stopped pushing audio")
        else:
            self._player.feed(data[prevPos:])
            if isDebugForSynthDriver():
                log.debug("Done pushing audio")
        self._processQueue()
Example #3
0
    def _callback(self, bytes, len, markers):
        if len == 0:
            # The C++ code will log an error with details.
            log.debugWarning("ocSpeech_speak failed!")
            self._processQueue()
            return
        # This gets called in a background thread.
        stream = io.BytesIO(ctypes.string_at(bytes, len))
        wav = wave.open(stream, "r")
        self._maybeInitPlayer(wav)
        data = wav.readframes(wav.getnframes())
        if markers:
            markers = markers.split('|')
        else:
            markers = []
        prevPos = 0

        # Push audio up to each marker so we can sync the audio with the markers.
        for marker in markers:
            if self._wasCancelled:
                break
            name, pos = marker.split(':')
            index = int(name)
            pos = int(pos)
            # pos is a time offset in 100-nanosecond units.
            # Convert this to a byte offset.
            # Order the equation so we don't have to do floating point.
            pos = pos * self._bytesPerSec // HUNDRED_NS_PER_SEC
            # Push audio up to this marker.
            self._player.feed(data[prevPos:pos],
                              onDone=lambda index=index: synthIndexReached.
                              notify(synth=self, index=index))
            prevPos = pos
        if self._wasCancelled:
            if isDebugForSynthDriver():
                log.debug("Cancelled, stopped pushing audio")
        else:
            self._player.feed(data[prevPos:])
            if isDebugForSynthDriver():
                log.debug("Done pushing audio")
        self._processQueue()
Example #4
0
	def cancel(self):
		# Set a flag to tell the callback not to push more audio.
		self._wasCancelled = True
		if isDebugForSynthDriver():
			log.debug("Cancelling")
		# There might be more text pending. Throw it away.
		if self.supportsProsodyOptions:
			# In this case however, we must keep any parameter changes.
			self._queuedSpeech = [item for item in self._queuedSpeech
				if not isinstance(item, str)]
		else:
			self._queuedSpeech = []
		if self._player:
			self._player.stop()