Is Teensy3.6+Audioshield able to detect audio playhead position?

Status
Not open for further replies.

LeeHenderson

New member
Forgive me if this is answered elsewhere, but I couldn't find it.

I'm building a looper using Teensy and its audio shield. I made a working version that takes a line-level input from any sound source, and will loop a section of whatever you feed into it, and that works great. But the external sound source keeps going, obviously, unaware it's being looped, so switching back to it produces a jump cut.

My new objective is to have the Teensy play back a file from the SD card; when the loop button is pressed once, it registers the current playhead position as the start of the loop and continues playing, and when it's pressed a second time it registers that playhead position as the end of the loop and jumps back to the start of the loop—the idea is that it would then play that looped section over and over until the loop button is pressed a third time, at which point it would finish its current loop and resume normal playback, seamlessly. The "loopStart" and "loopEnd" values would get wiped as it waits for new loop-button-presses.

Is this possible with the Teensy? I couldn't find a way to either write or read a specific playhead position in the audio file... would this be done by reading the number of the sample, or the milliseconds/microseconds into the file, etc.? Beyond that, I'm fairly certain I know how I would write the sequence of events as different operational modes (start playback, start loop, end loop, resume unlooped playback, etc.)

Thanks for any help anyone can provide!

p.s. - I've just been using the Audio.h library from PJRC, but feel free to redirect me if there's a better solution...
 
Let's assume you have an AudioPlaySdWav object called "playWav", you could do the following: loopStart = playWav.positionMillis() and loopEnd = playWav.positionMillis().

The easiest way to find this kind of info is using the GUI editor tool (https://www.pjrc.com/teensy/gui/). Click on each object type and it will display info about the object, including what methods it has available, and where the examples are located.
 
Thanks, wcalvert, for your reply!

I can measure the position as you suggest, so that's gotten me halfway there—a button press registers loopStart in milliseconds, and a second press registers loopEnd. Thanks!

But I can't seem to find a way to jump the "playhead" (as it were) to a specific position (loopStart) once I've measured it, despite combing through the Function descriptions in the GUI tool, nor by looking inside of play_sd_wav.h, play_sd_wav.cpp, etc...

So positionMillis only spits out values and doesn't seem to accept new ones as arguments, unless I've got the syntax wrong. What I mean is:
"playSdWav1.positionMillis(32000);"
for example, doesn't jump to 32 seconds into the file, and indeed throws an error if any integer is placed between those brackets. So it'll read a current position, but not "write" one, as far as I can tell. I couldn't find a way to jump forward or back by a certain number of milliseconds, either, otherwise I could just rewind by an amount equal to (loopEnd - loopStart).

The function "play()" seems only able to call a specific file rather than a file and a starting position, as it won't accept any arguments beyond the file's name.

Am I out of luck?

Thanks!
 
You're right, there isn't a method to seek to a certain position within a file. That would absolutely be a great enhancement... I didn't realize that at first.

Based on the discussion I've seen here and on github, I think there might be some interaction with the SD library (file seeking / keeping the file open, etc). I believe the SD library is getting some upgrades for Teensy 4.0, so perhaps it would be hard to implement this feature right now... I'm not sure.

Then again, you might be able to hack the feature in fairly easily.
 
Thinking more about your problem, I think it might be possible to do it with the granular effect (and possibly a mixer?). It would go something like:

Sample starts playing. The sample is routed into the granular effect so it can capture the sample.
User presses first button, loopStart = playWav.positionMillis()
User presses second button, loopEnd = playWav.positionMillis()
Call begin() on the granular effect now that you know how long the loop length in milliseconds is.
Call playWav.stop() ... this will be needed later so we can seamlessly resume playing.
Call granular.beginFreeze(ms) to begin looping.
User presses third button to stop looping...
Call granular.end() at just the right time.
Call playWav.play() to seamlessly pickup playing where it left off before the loop.

As you can see, it's just a rough idea with a lot of unknowns. It would be fun to implement but I don't really have time to try it right now.
 
Thanks, wcalvert, this is amazing. I’ll definitely try playing around with the granular effect as a way to sidecar the loop segment. If it works that’s a deeply elegant solution.

I tried a version where I was recording the sound going out as it’s coming in (recording SD raw of the audio that was playing) but it was too taxing on the SD and just produced a kind of feedback glitching. The granular workaround is much more promising.

Thanks again! Will keep you posted and I’ll share the code if I get it working.
 
The one caveat I should mention is that, by using the granular effect, the maximum loop time will be limited by how much RAM you have available. On a Teensy 3.6, I believe there's enough RAM for 2.4 seconds, minus whatever's needed for overhead. Hopefully that would be enough for your application.

Anyway you're welcome and good luck!

PS - I'm so hoping the Teensy 4.0 comes with 1 meg of RAM. That would open up a *lot* of possibilities.
 
...

PS - I'm so hoping the Teensy 4.0 comes with 1 meg of RAM. That would open up a *lot* of possibilities.

Indeed T4 has 1 MB total - in two functional blocks of 512KB - So whatever part of the two halves are free to the user will be subject to what is unused - and what is available for what purposes …
 
Status
Not open for further replies.
Back
Top