microbit-foundation / micropython-microbit-v2

Temporary home for MicroPython for micro:bit v2 as we stablise it before pushing upstream
MIT License
43 stars 24 forks source link

AudioFrame behaviour is different for V1/V2 #47

Closed microbit-mark closed 1 month ago

microbit-mark commented 3 years ago

The example given behaves differently on V1 and V2

import audio
import math
def repeated_frame(frame, count):
    for i in range(count):
        yield frame
frame = audio.AudioFrame()

while 1:
    for i in range(len(frame)):
        frame[i] = int(math.sin(math.pi*i/16)*124+128.5)
    audio.play(repeated_frame(frame, 100),wait=True)

And the one in https://microbit-micropython.readthedocs.io/en/v2-docs/audio.html# seems to have another behaviour where the square wave is combined with the sawtooth one rather than being distinct from it.

From user:

I tried the previous program which can write 32 points of a beep that is repeated. I saw that in your document, these 32 points were sent over a period of 4ms. So with the following program we should hear a sound of 250Hz. One period on 32 points of the frame.

If instead of dividing by 16, we divide by 8, we should with a sound at 500Hz.

Using a smartphone application that does the FFT, I can't see the spectral line at 250Hz or 500Hz in my spectrum? A priori the sound intensity of your speaker is far too low. Obviously we can only generate multiple sounds of 250Hz. Obviously it will be difficult to go beyond 1000Hz a priori, because the sinusoid on 32 points is then too distorted.

I made a very simple little program with the V1 and with an external speaker grove. This program allows me to generate sound at the exact frequency. This program works perfectly

microbit-mark commented 3 years ago

@martinwork can you take a look if you are able to this week.

martinwork commented 3 years ago

@microbit-mark Will do!

martinwork commented 3 years ago

The code that plays the AudioFrame in V2 is completely different to the V1 code. I don't know enough about the CODAL audio pipeline right now to be able to tell if the V2 problem is in CODAL or micropython.

The data supplied to uBit.audio.mixer by the AudioSource class is the AudioFrame expanded BUFFER_EXPANSION times by linear interpolation, but the sample rate is multiplied by BUFFER_EXPANSION / 4.

I've experimented in C++ with supplying similar data to MemorySource (which is similar to AudioSource) and that doesn't sound right either.

AudioSource https://github.com/microbit-foundation/micropython-microbit-v2/blob/a76e1413bcd66f128a31d98756fc3d1f336d1580/src/codal_app/microbithal_audio.cpp#L30

audio_init https://github.com/microbit-foundation/micropython-microbit-v2/blob/a76e1413bcd66f128a31d98756fc3d1f336d1580/src/codal_port/modaudio.c#L113

linear interpolation https://github.com/microbit-foundation/micropython-microbit-v2/blob/a76e1413bcd66f128a31d98756fc3d1f336d1580/src/codal_port/modaudio.c#L80

jaustin commented 3 years ago

@dpgeorge I think this is related to the reproducing case you are building for Joe? This would be great to fix because there are a number of fun tutorials around for how to play wav from a micro:bit with MicroPython and they don't, at present, work well on V2.

dpgeorge commented 3 years ago

I have been trying to reproduce the "buffering" problem in pure C++ but I can not do it. So at this stage I'd suggest working around any buffering issues by just making it work correctly from the MicroPython side.

microbit-carlos commented 3 years ago

I'm not too familiar with this buffering issue, is there a CODAL ticket present already, or were we pending the C++ reproducer?

Is this something is still worthing opening in a ticket over there even if it is worked around in the MicroPython side?

dpgeorge commented 3 years ago

is there a CODAL ticket present already, or were we pending the C++ reproducer?

AFAIK there is no CODAL ticket for this, mainly because I cannot pin point it enough to describe it in technical detail. This was first seen with the initial issues with speech when moving it over to use the mixer, and fixed only by adding some extra buffering to the speech output. I'm still not sure why it doesn't work without the buffering, but the plan is to do a similar buffering for audio.play.

microbit-carlos commented 3 years ago

Okay, thanks for the clarification Damien. We are expecting a CODAL tag at the end of today and probably do a MicroPython release tomorrow. Will this work fit for the beta.5 or do we need to move it to beta.6?

dpgeorge commented 3 years ago

Will this work fit for the beta.5 or do we need to move it to beta.6?

I will try!

dpgeorge commented 3 years ago

Audio output should now be improved, see commit 96792630800cd821272d985200c35e1435eb2cd9

I'm not sure if it's exactly the same as v1, it will need to be tested on a variety of examples.

dpgeorge commented 3 years ago

CODAL v0.2.25 was updated in 76054c2e9445d8eea285132c2374a18ddc690514 and that improved the sampling rate accuracy of audio.play.

microbit-carlos commented 3 years ago

Great, thanks Damien! @microbit-mark would you be able to test this issue again with the hex from https://github.com/microbit-foundation/micropython-microbit-v2/actions/runs/655946723 ?

microbit-mark commented 3 years ago

The example in https://microbit-micropython.readthedocs.io/en/v2-docs/audio.html# still sounds different on V1 and V2. On V2 There is an audible click between samples that is less evident on V1.

I will ask the person on the support ticket to also test.

kevinjwalters commented 3 years ago

@microbit-mark If the PWM output is well behaved and the samples start and end at the midpoint you shouldn't get any clicks/pops at start/end?

dpgeorge commented 2 years ago

This repo was updated to use CODAL v0.2.35 in 76c1b3153970e967401dee6a2566fbfec36d8fe2, which changed the audio sampling time from 50ms to 5ms, to make V2 behave more like V1.

jaustin commented 2 years ago

@martinwork as with #67 could you please test with the version of MicroPython in https://python.microbit.org/v/beta and close this if the issue is now resolved?

martinwork commented 2 years ago

@jaustin I loaded the original python sample into beta and WebUSB downloaded it.

V1 makes a tone with lots of crackles, and clicks between. V2 makes a very quiet tone with a machine noise and stops after a few seconds with an error: usually "line 5 ValueError: generator already executing"; occasionally "line 11 ValueError: generator already executing"

Is it already known that switching to the beta editor tab resets micro:bit?

microbit-carlos commented 2 years ago

I can confirm that with the latest MicroPython (2b57ddd5344ebeeee736b513459bf23af5df1675, which has been updated to CODAL v0.2.40), this script still throws the ValueError: generator already executing errors.

dpgeorge commented 2 years ago

The ValueError: generator already executing problem should be fixed by 3b5652898eb3d1e9850e9e99db854a0e49043df3.

microbit-carlos commented 1 year ago

As difference in V1 and V2 was shipped in v2.0.0, and we have tight deadline for v2.1.0, we'll push this one to v2.2.0.

microbit-carlos commented 1 month ago

Some of the differences in the original code were due to the CPU speed change between V1 and V2, as V2 can process the sine wave quicker and constantly entering and exiting audio.play in an infinite loop.

This modified example better shows the output sound difference between V1 and V2 when outputting a sine wave on pin0, which needs headphones.

import audio
import math
import microbit

def repeated_frame():
    frame = audio.AudioFrame()
    for i in range(len(frame)):
        frame[i] = int(math.sin(math.pi*i/16)*124+128.5)
    while True:
        yield frame

if hasattr(microbit, 'speaker'):
    microbit.speaker.off() 

audio.play(repeated_frame(), wait=True)

audioframe-play-diff-v1-v2 (5).hex.zip

This video shows how they sound with an external speaker, using headphone the sound is very similar. The beginning with a V1 is a bit quiet, but hopefully still good enough to hear the difference

https://github.com/user-attachments/assets/ac0858f0-1bb6-4541-95a4-cbeedf8d2303

microbit-carlos commented 1 month ago

Okay, the test above on a V2 was with MicroPython v2.1.2 from the Python Editor. Using the latest build from the recording and playback branch and the sine wave on the V2 sounds much much better. Maybe sounded a bit more triangular than the V1, as it was louder as well, but close enough.

I think this is as close as we are gonna get, so we can close this as completed.