pyobjc icon indicating copy to clipboard operation
pyobjc copied to clipboard

Add Speech Synthesis?

Open abelsonlive opened this issue 2 years ago • 3 comments

Is your feature request related to a problem? Please describe. Hi! I love your work on this project and I'd love to help. I would like to add wrappers for the Speech Synthesis Framework but would need help getting started.

Additional context I'm interested in this because I've been working on a project called saysynth which turns this framework into a synthesizer. Right now that just works via the say command and subprocesses, but I'm curious about building an interface around it.

abelsonlive avatar Sep 15 '22 15:09 abelsonlive

Something like this should work:

import AVFoundation
import Cocoa

utterance = AVFoundation.AVSpeechUtterance.speechUtteranceWithString_("The quick brown fox jumped over the lazy dog.")

# Configure the utterance.
utterance.setRate_( 0.57)
utterance.setPitchMultiplier_( 0.8)
utterance.setPostUtteranceDelay_( 0.2)
utterance.setVolume_( 0.8)

# Retrieve the British English voice.
voice = AVFoundation.AVSpeechSynthesisVoice.voiceWithLanguage_("en-GB")

# Assign the voice to the utterance.
utterance.setVoice_(voice)

# Speak the utterance
synth = AVFoundation.AVSpeechSynthesizer.alloc().init()
synth.speakUtterance_(utterance)

# Run the eventloop for a while
# (this is a bodge, it would be better to use
#  a delegate to know when the system stops 
#  speaking and stop the runloop at that point)
Cocoa.NSRunLoop.currentRunLoop().runUntilDate_(Cocoa.NSDate.dateWithTimeIntervalSinceNow_(10))

That said, there are some problems with metadata in het AVFoundation bindings on macOS 12 due to the use of undocumented classes, see #492). That shouldn't affect this code though.

ronaldoussoren avatar Sep 15 '22 16:09 ronaldoussoren

Thank you for the quick response! I tried this out (installing via pip3 install -U 'pyobjc[allbindings]') and found that all methods under AVFoundation.AVSpeechUtterance returned None. Eg:

import AVFoundation
utterance = AVFoundation.AVSpeechUtterance.speechUtteranceWithString_("The quick brown fox jumped over the lazy dog.")
print(utterance)
# >>> None

Any thoughts? I am on Mac OS Mojave 10.14.16 and Python 3.10.6. Do I need to go through the steps to run this into an application?

abelsonlive avatar Sep 15 '22 21:09 abelsonlive

Here's my example app with same None issue : https://gitlab.com/gltd/say-cocoa

abelsonlive avatar Sep 15 '22 21:09 abelsonlive

It works for me:

>>> import AVFoundation
>>> utterance = AVFoundation.AVSpeechUtterance.speechUtteranceWithString_("The quick brown fox jumped over the lazy dog.")
>>> print(utterance)
[AVSpeechUtterance 0x6000007a5d80] String: The quick brown fox jumped over the lazy dog.
Voice: (null)
Rate: 0.50
Volume: 1.00
Pitch Multiplier: 1.00
Delays: Pre: 0.00(s) Post: 0.00(s)

I've also checked that the script I posted earlier actually speaks, and likewise for your sample project. I tested using the framework install for Python 3.10.7 from python.org (using a venv virtual environment)

How did you install Python? Is it a framework install?

ronaldoussoren avatar Sep 24 '22 10:09 ronaldoussoren

Closing this because I cannot reproduce the problem.

This likely is a problem with the Python install, in particular a lot of system frameworks require that the calling code is in an application or plugin bundle, which the Python.org framework install provides. A regular "unix" install does not.

ronaldoussoren avatar Oct 21 '22 11:10 ronaldoussoren