-
Notifications
You must be signed in to change notification settings - Fork 26
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
WIP: Audio recording and playback #163
base: master
Are you sure you want to change the base?
Conversation
@microbit-carlos Please try out the test program and see how it goes. |
I have updated this PR with the following additions/changes:
|
c800ba5
to
42e386d
Compare
Some tweaks have been made to how the "used_size" entry in @microbit-carlos this is now ready for wider testing. |
Thanks Damien! Diff: |
42e386d
to
87f726c
Compare
@microbit-carlos I have now updated this PR to use CODAL v0.2.66. It's working well. |
src/codal_port/microbit_microphone.c
Outdated
microbit_hal_microphone_start_recording(audio_frame->data, audio_frame->alloc_size, &audio_frame->used_size, audio_frame->rate); | ||
|
||
return mp_const_none; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is missing the wait flag implementation.
For example, with this bit of code, the display shows "R" inmediately:
my_recording = audio.AudioFrame(duration=3000)
microphone.record_into(my_recording, wait=True)
display.show("R")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait
is now implemented.
With this example the playback rate doesn't seem to change for playback. from microbit import *
RECORDING_SAMPLING_RATE = 7812
while True:
if pin_logo.is_touched():
# Record and play back at the same rate
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
audio.play(my_recording)
del my_recording
if button_a.is_pressed():
# Play back at half the sampling rate
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
audio.set_rate(RECORDING_SAMPLING_RATE // 2)
audio.play(my_recording)
del my_recording
if button_b.is_pressed():
# Play back at twice the sampling rate
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
audio.set_rate(RECORDING_SAMPLING_RATE * 2)
audio.play(my_recording)
del my_recording
sleep(200) Edit: Ah! the type was that this example was using |
Also, I think the |
Another small one, if the AudioFrame rate is set to a negative number it overflows the calculation (well, maybe it's converting it to an unsigned int at some point):
It could throw a ValueError instead, like setting it to zero:
|
Looks like
And on that note, should the rate be limited to 16 bits? Should it be increased to 32? |
Should I was also wondering if we should also make it a static function to be able to do |
Does the AudioFrame returned by
|
Passing a negative value to the And setting the
|
I have now removed |
Yes, correct, it still needs to be implemented. Would this just call CODAL's |
This was a mistake, it was supposed to be checking for negative rates. Now fixed.
I also fixed this, and increased the internal rate variable to 32-bits (I thought 16-bit would be enough for the rate, but it doesn't cost anything to make it 32-bits). |
87f726c
to
0b06914
Compare
Yes, only need to call the
|
The existing sim implementation of playing AudioBuffers has always been problematic because of the 4ms chunk size. For audio frames of longer duration I had more hope, but at the moment the chunk size used is the same even though we likely have a much larger buffer in the frame itself. Our work-in-progress record/playback sim implementation works OK if you increase LOG_AUDIO_CHUNK_SIZE from 5 to 6. (it's possible that on slower computers a bigger buffer still might help, I've not had a chance to test yet). We can't just do that as I think it means regular audio frames are pitch/rate shifted but it might show a way forward for the sim. The sim changes without the LOG_AUDIO_CHUNK_SIZE change can be seen here: |
@dpgeorge We've been testing the latest version from this PR and came up with a few discussion topics and bug reports. As there is a few of them, I've created individual GH issues to be able to track each of them individually, and all of them are in the v2.2.0-beta.1 milestone. Some of the issues are bug reports or fairly straightforward questions, but the following issues require further discussion:
@jaustin @microbit-matt-hillsdon your input on these would also be very welcomed. |
0b06914
to
c91ae4e
Compare
The following changes have been made to this branch/PR:
|
This needs discussion. This method should probably just set
How about allowing passing an |
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
No longer needs to be a multiple of 32. Signed-off-by: Damien George <[email protected]>
And allow duration to be a float, for more accurate sizing. Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
This is more efficient than mp_sched_schedule(), and can never fail. Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
It's no longer needed now that there is AudioTrack. Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
Signed-off-by: Damien George <[email protected]>
2dcd909
to
df4cb05
Compare
This PR adds audio/microphone recording and playback capabilities, as per the docs proposal: bbcmicrobit/micropython#791
It currently supports:
audio.AudioFrame(size)
to create large audio framesaudio.play(audio_frame)
can now take a singleAudioFrame
to playaudio.set_rate(rate)
can set the playback rate on the flyaudio.sound_level()
returns the current sound level being playedmicrophone.record_into(buffer, rate, wait)
to record audiomicrophone.is_recording()
to check if recording is ongoingmicrophone.stop_recording()
to stop recordingThere is a test program called
src/test_record.py
which uses all the above to show how it works.