Skip to content

Commit ad170fb

Browse files
ZDStudiosclaude
andcommitted
A Sound category, and a Sound tab that proves your speakers work
Making a noise from Python meant installing something, and the usual first choice, pyttsx3, says nothing at all until runAndWait is called. So the honest answer to "why can I hear nothing" was rarely obvious. Every computer already has a voice and a speaker; the trouble is that each one is reached a different way. Windows has the voices behind Narrator, macOS has say, Linux has espeak. The new Sound category hides that difference behind twenty two blocks that work everywhere with nothing installed: say out loud, start saying, set voice, set speaking speed, save speech to a file, play note, play drum, play a frequency in any of five wave shapes, tempo, rest, play and start a sound file, stop, volume. Tones, notes and drums are worked out one sample at a time and written as real wav files, so there is no synthesiser to install either. Each one is calculated once and kept, so a note inside a loop stays fast. The voice dropdown lists the voices this computer really has, looked up in the background so the window never waits for it. The Sound tab on the right is where you go when nothing can be heard. Test my speakers plays three notes and says so; if you hear nothing, the mute switch or the output device is the culprit rather than your program. Type a sentence, choose a voice, drag the speed and volume, press Say it. Put these blocks in my project then drops blocks that do exactly what you just heard. It runs the same helper functions the blocks compile to, so the tab and your program can never drift apart. For anyone who would rather use pyttsx3, gtts or playsound there are now hand written blocks for those too, and the pyttsx3 ones always call runAndWait. Also here: the side strip gives its twelfth category room, the panel tabs no longer clip, and the block drawer starts a little wider. Version 1.5.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent eb2f530 commit ad170fb

4 files changed

Lines changed: 1126 additions & 23 deletions

File tree

README.md

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
[![Python](https://img.shields.io/badge/python-3.9%2B-4C97FF?logo=python&logoColor=white)](https://www.python.org/)
1010
[![Dependencies](https://img.shields.io/badge/dependencies-none-59C059)](#)
11-
[![One file](https://img.shields.io/badge/one%20file-7%2C000%20lines-FFAB19)](scratchpy_studio.py)
11+
[![One file](https://img.shields.io/badge/one%20file-9%2C700%20lines-FFAB19)](scratchpy_studio.py)
1212
[![Build](https://github.com/ZDStudios/scratchpy-studio/actions/workflows/build-apps.yml/badge.svg)](https://github.com/ZDStudios/scratchpy-studio/actions/workflows/build-apps.yml)
1313
[![Download](https://img.shields.io/badge/download-windows%20%7C%20macos%20%7C%20linux-855CD6)](https://github.com/ZDStudios/scratchpy-studio/releases/latest)
1414
[![License](https://img.shields.io/badge/license-MIT-0FBD8C)](LICENSE)
@@ -49,11 +49,12 @@ and hand in.
4949

5050
| | |
5151
|---|---|
52-
| 🧩 **148 blocks** | Hat blocks, C-shaped loops, hexagonal booleans, reporter ovals that drop into slots — the real Scratch 3 shapes and colours |
52+
| 🧩 **177 blocks** | Hat blocks, C-shaped loops, hexagonal booleans, reporter ovals that drop into slots — the real Scratch 3 shapes and colours |
5353
| 🐍 **Real Python, live** | The generated source updates as you drag. No hidden interpreter |
5454
| ▶️ **It actually runs** | `print`, `input`, errors and a stop button, all wired to the built-in console |
5555
| 👆 **Click a block to try it** | A loose block runs on its own and reports what it printed in a bubble underneath |
5656
| 🌐 **Talks to the web out of the box** | GET, POST, headers, JSON, downloads — using `urllib` from the standard library, so there is nothing to install |
57+
| 🔊 **It talks** | A Sound category that speaks, plays notes and beats drums — using the voice and speaker the computer already has |
5758
| 📥 **Import any `.py`** | Turn a program you already have into blocks — loops, functions, try/except, f-strings and all |
5859
| 📦 **Every PyPI package** | pip dashboard installs anything and turns it into blocks automatically |
5960
| 🤖 **Works with AI** | Built-in MCP server so an assistant can build blocks alongside you |
@@ -147,6 +148,56 @@ test is exactly what your program will do.
147148

148149
---
149150

151+
## It talks. Nothing installed.
152+
153+
Every computer already has a voice and a speaker — the trouble is that each one
154+
reaches them a different way. Windows has the voices behind Narrator, macOS has
155+
`say`, Linux has `espeak`. The **Sound** category hides the difference, so one
156+
block works on all three.
157+
158+
<div align="center">
159+
<img src="docs/screenshot-sound.png" width="900" alt="The Sound category and the Sound tab">
160+
</div>
161+
162+
| Block | What it does |
163+
|---|---|
164+
| `say [hello] out loud` | Speaks, and waits until the sentence is finished |
165+
| `start saying [hello]` | Speaks while the program carries on |
166+
| `set voice to (▾)` | The dropdown lists the voices *this* computer really has |
167+
| `set speaking speed to (0)` | −10 is very slow, 10 is very fast |
168+
| `save speech [hello] to [speech.wav]` | Keeps it as a real sound file |
169+
| `play note (C4▾) for (0.5) beats` | Middle C is `C4` or `60`; `F#3` and `Bb4` work too |
170+
| `play drum (snare▾) for (0.25) beats` | Twelve drums, synthesised from scratch |
171+
| `play (440) Hz for (0.5) seconds` | Any frequency, plus sine, square, saw, triangle and noise |
172+
| `set tempo to (120) beats a minute` · `rest for (0.25) beats` | Music timing, the way Scratch does it |
173+
| `play sound [sound.wav]` · `start sound [sound.wav]` | Your own files — `.wav` everywhere, `.mp3` on Windows and macOS |
174+
| `stop all sounds` · `set volume to (100) percent` | Silence, and loudness |
175+
176+
Tones, notes and drums are worked out one sample at a time and written as real
177+
`.wav` files, so there is no synthesiser to install either. Each one is
178+
calculated once and then reused, so a note inside a loop stays fast.
179+
180+
### Can you hear this?
181+
182+
The **Sound** tab on the right is a place to make a noise *now*, before you have
183+
built anything:
184+
185+
- **Test my speakers** plays three notes. If you hear nothing, the problem is
186+
the mute switch or the output device, not your program — and it says so.
187+
- Type a sentence, pick a voice, drag the speed and volume, press **Say it**.
188+
- A little keyboard for trying notes and a drum.
189+
- **Put these blocks in my project** drops blocks that do exactly what you just
190+
heard, sliders and all.
191+
192+
It runs the *same* helper functions your blocks compile to, so what you hear in
193+
the tab is what your program will do.
194+
195+
> Using `pyttsx3` instead? Its catch is that nothing is heard until
196+
> `runAndWait()` is called. ScratchPy now ships hand-written blocks for it that
197+
> always do both — as it does for `gtts` and `playsound`.
198+
199+
---
200+
150201
## Bring your own Python
151202

152203
Press **Import .py** and pick any file. The whole program becomes blocks.
@@ -357,7 +408,7 @@ writes a tidy module with a `main()` and an `if __name__ == "__main__":` guard.
357408
python scratchpy_studio.py --selftest
358409
```
359410

360-
Builds the entire interface head-lessly, then **compiles every one of the 148
411+
Builds the entire interface head-lessly, then **compiles every one of the 177
361412
blocks**, checks the block definitions are well formed, round-trips a project
362413
through save and load, exercises the Python importer and the MCP server, and
363414
finally runs the generated example program and checks its output.

build_apps.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ def build():
7474
"--add-data", ASSETS + os.pathsep + "scratchpy_assets"]
7575

7676
if system == "Windows":
77-
args += ["--icon", os.path.join(ASSETS, "scratchpy_icon.ico")]
77+
args += ["--icon", os.path.join(ASSETS, "scratchpy_icon.ico"),
78+
# the sound blocks reach for winsound from inside a string of
79+
# generated code, so PyInstaller cannot see it by itself
80+
"--hidden-import", "winsound"]
7881
elif system == "Darwin":
7982
args += ["--icon", os.path.join(ASSETS, "scratchpy_icon.icns"),
8083
"--osx-bundle-identifier", "com.scratchpy.studio"]

docs/screenshot-sound.png

107 KB
Loading

0 commit comments

Comments
 (0)