Streamed waveform keeps changing sampling rate #4596
Replies: 1 comment
-
Posted at 2015-04-19 by @allObjects Can you post the exact code you run? Posted at 2015-04-19 by Dennis For convenience I added a watch to Button 1. When the button is pressed, the play function is run, which illuminates LED1 and streams the raw file from the SD card to analog pin A4 as a waveform. When playing is done, it turns off the LED.
Posted at 2015-04-19 by @allObjects What I think happens is - since you do not debounce your button - that multiple play() run at the same time, and due to interference with time/phase constantly shifting funny sounds... (to verify that, put in our current code Therefore, do something like this for watching your button:
xxxxx is either rising or falling - both is working (if you do not hold on to the button until play has finished). You put this line as line 27 and you also insert it into your stop after line 14 (in which you switch your LED1 off). When this is working - with xxxx the way that the play starts only after you have released the button - you can then make it stop when pressing and releasing the button while it is playing. Looking forward to hear from you! PS: I did not work with files yet on Espruino, but I wonder if you need to do something like close(), do you? Posted at 2015-04-19 by Dennis Thank you, it is certainly a good thing to de-bounce the button. The problem is not related to bouncing though, because the exact same problem occurs if I only send the contents of the play function to the board and no button is involved. It really sounds like the sample output rate changes every few thousand samples... which is strange, since it is only set once in w.startOutput. Any other ideas? Posted at 2015-04-19 by @allObjects Fort the stop play: Make this line
the very first line in your code and insert after the line in which you turn the LED1 on these lines:
Then add in the stop before the line with w.stop(); this line:
Posted at 2015-04-19 by @allObjects Interesting... no other idea right now... Posted at 2015-04-19 by @allObjects ...but the code assumes that there is at least data available to fill three buffers (or at least the first two fully and the third partially)... because I do not see any checks before these three buffers are getting used. May be the implementation is tolerant to the case were not even the first buffer is full... ;) I'm also not sure if stopping at the moment when reading ahead the content for the next buffer switch is correct... the waveform may still have things to play off of the buffer to which it just has switched. @gfwilliams will for sure provide the needed insight here! Posted at 2015-04-19 by Dennis The sample is long enough to fill 3 buffers (30 kbytes should fill 15 buffers of 2048 bytes). Note that this code comes from the original Espruino documentation. Even if I copy it without any changes (such as the button interface), I get that problem. The JavaScript should be fine and it looks fine to me... so the problem is perhaps rooted even deeper (in the firmware, on a level below the JS interpreter)? I don't know what happens under the hood, so I can only speculate, but is it possible that something (reading from the SD?) is slowing down the waveform output loop (hence the lower output frequency) and then some regulative code in the firmware compares the actual output position to the supposed one and speeds up the output in order to "catch up" (hence the higher output frequency)? Not sure if it matters, but I have a bluetooth module soldered onto the board (which I am not using at the same time) Posted at 2015-04-20 by Dennis Update: I just flashed the latest firmware onto the board and the behavior changed. Now the sampling rate seems to remain constant. The original issue (changing sampling rate) is fixed :-D Instead, I now get a different problem: little bits of the audio are repeating. This looks very much like the buffers cannot be re-filled fast enough and the playback runs into old data before the new data is ready. That sucks, but it's much less mysterious. Some experimenting has shown that with a buffer size of 1024 samples, the maximum sampling rate achievable without audible artifacts is 10000 Hz. For a buffer size of 2048, it's 14000 Hz. I cannot make the buffer much bigger, since Espruino will run out of memory. The documentation metions output rates of 20 KHz... has anybody achieved better results than me, while streaming from an SD? Posted at 2015-04-20 by DrAzzy Oh yeah - Gordon fixed some issues with waveform recently, that'd be that. It might be loading the data off the SD card that's slowing it down? Also, what's the default SPI clock speed? I wonder if it's slow enough that the SPI data transfer time is an issue? You could try specifying a higher baud, and see if that helps. Can you post the latest code you're using? Posted at 2015-04-20 by @gfwilliams
Yes, that'll be the time it takes Espruino to load the data off the SD card. As @drazzy says, you might be able to bump the clock rate of the SD card's SPI up:
But I don't think you'll get a huge amount better. While the documentation mentions 20KHz, that's when playing a file that's already loaded into RAM - trying to stream it off the SD card as well is substantially more painful for Espruino. Posted at 2015-04-20 by @allObjects @gfwilliams, you mentioned a while ago on my memory manager thread something about DMA... could that help? Something like a module that let's you setup a DMA between two connected devices/'comm protocols'? It can evade the back and forth between fast firmware and slower source interpreted JS? The module should be an on-demand loadable module but would for need pieces in the firmware. The firmware pieces are like a switch board or clearing / routing house for data in transfer. I see the available firmware memory melt away like snow in summer... Posted at 2015-04-21 by @gfwilliams DMA itself is relatively basic - 'read X bytes from Y and copy them to Z'. Handling FAT32 with it would be a no go. Potentially there's the ability to re-write bits of the FAT library to use DMA and become async, but that'd require a new filesystem API as well and is a big chunk of work :( So the other option is to use DMA for the Waveform output itself. That's definitely possible and could potentially be a second mode of operation for Waveforms. The problem I have is that when you move away from the current software solution, things are so interconnected that you can no longer hide the complexity from the user - which is what I've been trying to avoid with Espruino. If I did waveforms with DMA you wouldn't be allowed to do it if you were also using PWM on certain other pins because you need to hijack a timer from somewhere to drive DMA. Doing two waveforms would be even more tricky, and overlapping them on the same output would be impossible. Suddenly instead of copying 6 lines of JS from the website you've got to read a 1000 page STM32 reference manual. ... and if you're willing to read that manual you can actually set up DMA right now with the Posted at 2015-04-21 by Spocki Have a look at VS1053 breakout boards, ideally with SD card. Programmable by SPI, there arduino libraries and examples. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Posted at 2015-04-19 by Dennis
I have wired a headphone amplifier to pin A4 and copied the last example from this page:
http://www.espruino.com/Waveform
to stream a waveform from the SD card.
For some strange reason, the playback sampling rate does not remain constant. It seems that every time a new buffer is used, the sampling rate changes to a random value roughly in the range +/- 100%, so a recorded voice alternates between normal, Mickey Mouse and monster a few times per second.
What could be causing this? I am using the example code (only changed filenames). It doesn't matter if I try to play with 8, 11, 16 or 22 kHz, I always get this strange behavior.
Beta Was this translation helpful? Give feedback.
All reactions