Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mimxrt10xx: Add PWMAudioOut #7785

Merged
merged 6 commits into from
Mar 28, 2023
Merged

mimxrt10xx: Add PWMAudioOut #7785

merged 6 commits into from
Mar 28, 2023

Conversation

jepler
Copy link
Member

@jepler jepler commented Mar 23, 2023

.. via a peripheral known as the "MQS" (medium quality sound). It uses an ~192kHz PWM signal to generate audio. It sounds OK on a small speaker with no amplifier. There's a small pop when starting/stopping audio, as is typical.

tested with wave files & audiomixer on metro m7. Only these specific pins may be used (not that A1 has to be left channel and A0 has to be right channel):

        from audiopwmio import PWMAudioOut
        return PWMAudioOut(board.A1, right_channel=board.A0)

.. via a peripheral known as the "MQS" (medium quality sound). It uses an
~192kHz PWM signal to generate audio. It sounds OK on a small speaker with
no amplifier. There's a small pop when starting/stopping audio, as is
typical.
@jepler jepler requested a review from tannewt March 23, 2023 20:59
Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

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

If I use my test program (see below), and then ctrl-C it, then when I restart it, I get:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "play.py", line 14, in <module>
ValueError: I2SOut in use

This is confusing, because it's not known to the user that I2S is in use, and something is not being reset when the VM starts up (or shuts down).

import array
import board
import os
import time

from audiocore import RawSample, WaveFile

from audiopwmio import PWMAudioOut

def print_filenames(filenames):
    for num, filename in enumerate(filenames):
        print(f"{num:2d} {filename}")

pwm_out = PWMAudioOut(left_channel=board.A1, right_channel=board.A0)

wavs = []
for filename in (os.listdir()):
    if filename.endswith(".wav"):
        wavs.append(filename)
        wavs.sort()

print_filenames(wavs)

while True:
    inp = input("play: ").split()
    try:
        filenum = int(inp[0])
    except (IndexError, ValueError):
        print_filenames(wavs)
        continue

    if filenum >= len(wavs):
        print_filenames(wavs)
        continue

    if len(inp) > 1:
        try:
            mode = modes[inp[1]]
        except:
            print_filenames(wavs)
            continue

    filename = wavs[filenum]
    wav = WaveFile(open(filename, "rb"))

    print(f"  playing {filename}")
    pwm_out.play(wav)
    time.sleep(1.2)

ports/mimxrt10xx/common-hal/audiobusio/__init__.c Outdated Show resolved Hide resolved
ports/mimxrt10xx/common-hal/audiopwmio/PWMAudioOut.h Outdated Show resolved Hide resolved
@dhalbert
Copy link
Collaborator

Also the "." debugging printout continued to run after the playing was finished. Maybe that's just how the I2S hw is working, but it seems like the interrupt continues even when play is done:

>>> import play
note: peripheral 3
 0 mak11.wav
 1 mak12.wav
 2 mak14.wav
 3 mak15.wav
 4 mak16.wav
 5 mak17.wav
 6 mak22.wav
 7 mak22050.wav
 8 mak24.wav
 9 mak8.wav
play: 0
  playing mak11.wav
.............................................................................................................play: ....................................................................................................................................................................................................................................................................................................Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "play.py", line 25, in <module>
KeyboardInterrupt: 
>>> ..........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
[board reset here]

@jepler
Copy link
Member Author

jepler commented Mar 24, 2023

Yes, we keep feeding the peripheral with zeros (only signed 16-bit samples are ever output, so this is the "quiescent value"; the value specified by the user is always ignored) because otherwise the hardware signals FIFO underruns and gets grumpy. There may be a clever way to turn the FIFO off exactly when it empties, but it was easier to just keep giving it zeroed data.

@jepler
Copy link
Member Author

jepler commented Mar 24, 2023

OK I think I've fixed the problem with the imported version and the peripheral in use but I didn't re-test it. The class (as was i2sout!) was allowed to be relocated to long-lived, with bad consequences. And it had no del so without deinit the i2s peripheral would remain in use. However, I'll re-test locally before re-requesting review from you.

@jepler jepler requested a review from dhalbert March 27, 2023 15:53
Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

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

All the previous problems seem gone. One thing I notice is that if I play samples recorded at certain rates, the pitch changes. For instance a 440 Hz 11k .wav is not the same pitch as 8k,16k, or 32k, all of which are at the same pitch. Is this inherent in the way the MQS works? Should we forbid files whose sample rates are not evenly divisible into 192k, or just add a **Limitations**: warning?
sine-samples.zip

Copy link
Collaborator

@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

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

@dhalbert dhalbert merged commit 77cd20a into adafruit:main Mar 28, 2023
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.

2 participants