Skip to content

Conversation

@ArcaneNibble
Copy link
Collaborator

This is a basic speaker driver for the EV3. The API surface exposed to user code is the same Speaker class as other hubs.

Unlike v1, this driver directly generates a square wave of the desired frequency rather than playing back samples.

As a consequence, it does not support volume control. However, it plays the full note range better than v1.

@coveralls
Copy link

coveralls commented Jul 16, 2025

Coverage Status

coverage: 57.254%. remained the same
when pulling 9db628b on ArcaneNibble:audio
into c14499c on pybricks:master.

// The division factor of 40 gives decent coverage of the frequency range
// 64 Hz - 24 kHz that the other drivers support.
// (This is limited by the 16-bit period counter.)
#define PWM_TIMEBASE_FREQ (SOC_EHRPWM_0_MODULE_FREQ / 40)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily for this pull request, but we need to have a look at the clock tree.

In the official LEGO firmware and in ev3dev, we have the ASYNC3 clock mux selecting SYSCLK2 from PLL1 rather than PLL2. It is 132 MHz instead of 150MHz.

}

void pbdrv_beep_start(uint32_t frequency, uint16_t sample_attenuator) {
// This hardware doesn't implement volume control
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand what this is doing. Is this just changing the duty cycle? Shouldn't that only affect the timbre and not the volume?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a sufficiently narrow PWM pulse, I think the low pass filter starts to kick in and thus attenuates the signal and decreases the volume.

@ArcaneNibble
Copy link
Collaborator Author

Made some changes, but I don't quite understand how the volume control works. Could you please explain it?

@ArcaneNibble
Copy link
Collaborator Author

Apparently you're right, and this somewhat actually works. You can notice a timbre change around maximum volume, but it generally does get quieter once the duty cycle gets very short.

ArcaneNibble and others added 5 commits July 18, 2025 18:19
This now allows sound drivers to support only beeping,
only playing samples, or both.
Add a default volume configuration option for each platform that
supports sound. The EV3 speaker can be quite loud, so we don't want
it to default to 100%.
@dlech
Copy link
Member

dlech commented Jul 19, 2025

I rebased and added a commit to set the default volume to 75% since the beeps can be quite loud (also, I think this is what the official EV3 software does by default, so users could be expecting it).

@dlech dlech merged commit aa0e305 into pybricks:master Jul 19, 2025
17 checks passed
@dlech
Copy link
Member

dlech commented Jul 19, 2025

Once again, thanks for the excellent work!

@BertLindeman
Copy link
Contributor

BertLindeman commented Jul 19, 2025

running ci-build-4014-v3.6.1-281-g16e7a481 to test the speaker.
Entered this here as it seemed appropriate.
Can make a new issue if that is better.

The "REST" sound is a nasty BRRRR.

Also tested with:

# from pybricks.hubs import EV3Brick
from pybricks.hubs import ThisHub
from pybricks.tools import wait 

# hub = EV3Brick()
hub = ThisHub()

hub.speaker.volume(100)
notes = []
for octave in range(2, 9):  # 2 to 8
    for note in ["A", "B", "C", "D", "E", "F", "G"]:
        notes.append(note + str(octave) +"/8")
    notes.append("R/1")
for n in range(len(notes) / 8):
    print(notes[n*8:n*8+8])
    hub.speaker.play_notes(notes[n*8:n*8+8])
wait(500)

Could not upload the m3 files, so zipped them:
EV3 speaker.zip

Converted to mp4:
rest notes:

EV3.REST.250719_112219.mp4

octaves:

EV3.octaves.250719_112431.mp4

It may be my hearing but it seems on the primehub that on each octave from the A to the B note the pitch increases and to C it drops a bit and then the pitch goes up again.
Not sure though, do not have a musical ear.

@ArcaneNibble
Copy link
Collaborator Author

Oh that's fun. Apparently a rest plays a frequency of 0 Hz expecting that to turn the sound off, but that function wasn't implemented.

As for the pitch jumping around, that's just because the API is excessively music-theory-brained:

The octave changes to the next number at the note C, for example, B3 is the note below middle C (C4).

So A3 and B3 come after G3 and are far above C3.

@BertLindeman
Copy link
Contributor

Thanks, for the music theory, I am such a noob in that.
Asked 3 A.I. assistants and they confirmed my "program" was correct going up in pitch.

So I should use C D E F G A B per octave.

Sounds better!
And ~ nothing wrong in my hearing although the last notes of octave 7 and all of octave 8 I hear just the clicks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants