PDA

View Full Version : always record the last 30 seconds of audio?



jassing
02-12-2016, 07:02 PM
Hi -- I often find myself listening to (two-way) radio & paying closer attention to driving and asking "What did he say?". No one wants to hear that question over the radio. So I thought if I could use a teensy to record the last 30 seconds & then play it when a button is pressed, my problem solved.

However, I can't get around how to do this... Using an sd card seems impossible to do this; so some flash or other (volatile) memory and a circular buffer -- but conceptually, I can't figure out how to do this. Moreover, I can't think of a good way to play "the last 30 seconds" and continue recording new conversations.

I'd like to use the 'speaker out' so that there is an input & output line, sort of a man-in-the-middle box with 1 button "Play last 30 seconds"

Is this possible with teensy+audio board? Anyone have any clues for me to get started?

thanks.
-j

Constantin
02-12-2016, 09:31 PM
Maybe consider podcasts instead? Then you can use your car stereo system to go backwards as needed.

jassing
02-12-2016, 09:54 PM
I must not be familiar with this use of the term podcast.
so for this to work; I would listen to my two radio, then if I wanted to listen to the last 30 seconds, I would turn the car stereo on, tune it to some station and press some magic button to play the last 30 seconds?
I think this might be too much for arduino based on what I've read...
thanks for hte podcast idea; I'll try to find more information on it.

adrian
02-15-2016, 01:24 AM
I've heard of solutions like that .... for home recording studios .... so someone is noodling around, and hits a golden patch ... the last minute of audio is recorded! Good for jamming.

el_supremo
02-15-2016, 01:47 AM
You could record to a circular buffer stored in a flash memory chip and play back the buffer when a button is pressed.
Shouldn't be too tricky.

Pete

jassing
02-15-2016, 03:24 AM
So it's doable with teensy & audio board? What I'm not clear on, conceptually or technically, is how to record to a circular buffer (I know what a circular buffer is, just have an issue with audio, which is a continuous stream, whereas I am used to it with data which has starts & stops).
I am not asking for code (although I wouldn't ignore it) -- but I am looking A) is it doable with teensy&audio and B) where should I focus reading to get it going...
Thanks.

Constantin
02-15-2016, 04:37 AM
I'd still recommend downloading podcasts instead.

Podcasts are basically audio files that contain a program of choice. Many radio station now allow this service, it makes it much easier for audiences to catch programs. Download the podast to your phone, an iPhone, etc. and connect the device to your care entertainment system, and you are good to go. The main advantage is that this is a ready, off-the-shelf solution. Unlike a ring buffer that may fill over time as you use the 'back' button, the podcast has no issues with you wanting to go forward backward, pausing, etc.

For that reason, I think you'd be better off using a device with a podcast rather than listening to live radio and putting that audio stream into a ring buffer that may or may not fill up before you're done listening to all the content you're interested in.

WMXZ
02-15-2016, 09:29 AM
I'd like to use the 'speaker out' so that there is an input & output line, sort of a man-in-the-middle box with 1 button "Play last 30 seconds"

Is this possible with teensy+audio board? Anyone have any clues for me to get started?


Teensy audio unmodified records 44.1 kHz 16 bit.
So for 30 seconds mono you need a buffer of 2.646 MByte. On audio card you may get 128 kByte SRAM. Adding FrankB's memory board would give you 6*128 = 0.768 MByte SRAM (assuming 128 kByte chips).
So if you can live with a max delay of 8.7 second then teensy environment has hard and software available.

If you are only interested in voice recording and decimate acquired data by 4 (5 kHz bandwidth), and you are willing to do the programming, then 30 seconds delay is possible.

If you are going to play with hardware, maybe you could get 4 of FrankB's Memory boards, wire them properly together, adapt the recording software and record 32 seconds at 44.1 kHz mono.

PaulStoffregen
02-15-2016, 12:47 PM
I agree, Frank's memoryboard (https://github.com/FrankBoesing/memoryboard) with six 23LC1024 chips is probably the best solution. Maybe 9 seconds is enough for "what did he say?" ?

The memoryboard approach would be extremely easy too. Just run the audio into the delayExt object. Then use a mixer to route either the live or 9 second delayed signal to the output. Write a tiny program to change the mixer gains depending on the button. Very simple.

Doing this with a SD card might also be possible, but it'll be much harder. I believe it still should be possible....

The weak link will be the Arduino SD library. Several months ago I started an ambitious ground-up redesign of the SD library, to be usable from the main program and also interrupts, and to cache several sectors. However, that work is still at an early stage of development, with the main limitation being a lack of write support. Someday in a glorious but distant future, this work will lead to a far more capable SD library. But for now, you'll have to make do with the SD library we have. Or maybe bypass the library and FAT32 to directly access the SD card as raw sectors.

Because of the SD limitations, you won't be able to access the SD card from within the audio library. You'll need to use a pair of the queue objects to bring the streaming data in and out of your Arduino sketch. The good news is the queue objects automatically queue up arriving data if you (occasionally) need more time, and you certainly will on the occasions with the SD card takes longer to complete a write. The play queue also allows you to push in more than one packet of data quickly.

The SD library is faster if you always read 512 bytes at a time, of course aligned to the 512 byte sector boundaries. You'll want to structure your code to work with 512 byte chunks of data. Each of those corresponds nicely to 2 audio buffers.

You'll probably want to pre-allocate a huge 4 gigabyte file on the SD card. Perhaps you can arrange for the file to be contiguously allocated, which might let you completely bypass the filesystem to access it as raw sectors. But even if you go through the filesystem layer, creating the huge file in advance will save all the overhead of allocating space and writing changes to the FAT sectors.

How to both read and write from the file is a good question. Again, bypassing the filesystem (if the file isn't fragmented) and just reading and writing the raw sectors might be easiest. Using the SD library file operations, perhaps you can open the file twice, with one "File" for reading and and another for writing. If the file's size changes, that'll probably get terribly messed up. But maybe it'll work if the file's size and allocation doesn't change?

Anyway, as far as the audio library is concerned, this would involve a pair of the queue objects. You'd need to move the data between those and the media, which might not be too difficult, but it does mean writing code to rapidly move a lot of bytes around. That's quite a bit more complicated than using delayExt with the memoryboard and a trivial amount of code to reconfigure mixer gains to switch between the live and 9 second delayed signal.

Xenoamor
02-15-2016, 01:13 PM
Food for thought based on Paul's mention of RAW access
The SDFat lib allows raw read/write access without needing to know the finer details
Here's an example of this (http://www.aem.umn.edu/people/faculty/flaten/ballooningteacherworkshop2013/Arduino_Documentation/Arduino%20Libraries/SdFat/examples/RawWrite/RawWrite.ino)

jassing
02-15-2016, 07:22 PM
I'd still recommend downloading podcasts instead.
"downloading" implies connectivity to a server or other system... that wouldn't work in this case.


If you are only interested in voice recording and decimate acquired data by 4 (5 kHz bandwidth), and you are willing to do the programming, then 30 seconds delay is possible.

30 seconds was just a guess -- looking at real world, anything over 10 seconds (so 9 is close enough) would be fine. Finding the "not too short & not too long" will be fine tuning I can do later. I am interested in only voice; so I hadn't thought about filtering anything else out... Nice idea.

@PaulStoffregen (Thanks @xenoamor for the link) Thanks for the explinations. I think, just based on speed, I would rather go with shorter length & faster speed, and it sounds like, less complexity/simpler and just use the audio board & memory board and skip the sd card.

This is my 1st attempt at an audio based project, so currently most of this is over my head; but as with everything else, I had to learn it at some point. I just wanted to be sure it was doable before trying to force it to happen. Might need help with grasping concepts, but I am confident that it can be done.

Thank you -- I will order up the parts & read up on delayExt objects.

jassing
02-16-2016, 02:52 AM
I do not yet have the audio board, so this is all air code, am I on the right track?
(The filter, I hope, will be used to trim out non-voice frequencies)

It looks like it does everything in stereo, is there a way to use mono & reduce the memory footprint?

A question that comes to mind is how do I get how much memory is A) available and B) used? for example; let's say 50% of ram is used up; and I hit "play delay" it would play that & not the full length since it doesn't exist -- since this could be a timer to resume "normal" audio, I need to know how much time is used up...

again, just air code to make sure I'm on the right track, I'm sure once I get it I can do more trial & error learning.
Thanks.


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S i2s1; //xy=95,41
AudioFilterBiquad filter1; //xy=222,80
AudioEffectDelay delay1; //xy=382,183
AudioMixer1 mixer1; //xy=525,95
AudioOutputI2S i2s2; //xy=675,34
AudioConnection patchCord1(i2s1, 0, filter1, 0);
AudioConnection patchCord2(filter1, delay1);
AudioConnection patchCord3(filter1, 0, mixer1, 0);
AudioConnection patchCord4(delay1, 0, mixer1, 1);
AudioConnection patchCord5(mixer1, 0, i2s2, 0);
// GUItool: end automatically generated code

#include <timerOne.h> // Will this work with audio card?

const byte pinPlayDelay = ???; // pin with interrupts
const byte pinDelaySetting = A1;
const byte pinGainSetting = A2;

const byte audioNormal = 0;
const byte audioDelay = 1;

global float float gainSetting = 1.0f;

volatile byte mixerInputChoice = 0; // 0=direct, 1=delay)

void setup() {
int byte i;

AudioMemory(???); // If I have ram installed on the audio board & franks board, what would I put here?
audioSheild.enable();
audioSheild.volume(0.5);

delay(1000);

audioShield.inputSelect(AUDIO_INPUT_LINEIN);
// audioSheild.micGain(24);

mixer1.gain(audioNormal,1.0);
for(i=1;i<4;i++)
mixer1.gain(i,0);

delay1.delay(0, ???); // max is 333 ms?
for(byte i=1;i<7;i++)
delay1.disable(i);

filter1.setLowpass(???); // stage, frequency, Q
filter1.setHighpass(???); // stage, frequency, Q
filter1.setBandpass(???); // stage, frequency, Q
filter1.setNotch(???); // stage, frequency, Q
filter1.setCoefficients(???); // stage, array[5]

attachInterrupt(digitalPinToInterrupt(pinPlayDelay ),PlayDelay,CHANGE);

Timer1.initialize( ??? ); // Need to know time of delay...
Timer1.attachInterupt( PlayDelay );
Timer1.stop();

}

void PlayDelay(){
/*
* This is only called when the button is pressed to play the delay audio
* or when "delay audio" run has expired.
* todo: how to know how much audio is in buffer? (and how to convert that to time)
*/

mixerInputChoice = !mixerInputChoice;

if (mixerInputChoice){
mixer1.gain(audioNormal, gainSetting);
mixer1.gain(audioDelay, 0);

attachInterrupt(digitalPinToInterrupt(pinPlayDelay ),PlayDelay,CHANGE);
Timer1.stop();
} else {
mixer1.gain(audioNormal, 0);
mixer1.gain(audioDelay, gainSetting);

detachInterrupt(digitalPinToInterrupt(pinPlayDelay ));
Timer1.start();
}
}

void loop() {
// float delaySetting = (float)analogRead(pinDelaySetting); // (adjust as needed) Used for user adjusting delay setting
// float gainSetting = (float)analogRead(pinGainSetting); // Allows user to adjust any gain from .5 to 1.5 (to avoid too much clipping)
// todo: adjust gainSetting to be in proper range. (.5 to 1.5)
// todo: adjust delaySetting to be in proper range (.5 to 9 seconds)

//delay1.delay(0, delaySetting);
//if(mixerInputChoice) // 0 = normal, 1 = delay
// mixer1.gain(audioNormal,gainSetting);
//else
// mixer1.gain(audioDelay,gainSetting);

delay(5);
}

PaulStoffregen
02-16-2016, 11:36 PM
First, watch the 48 minute tutorial video. It'll answer some of your questions, and give you a much better understanding of the audio lib (eg, mono vs stereo...)

https://www.youtube.com/watch?v=wqt55OAabVs

You should probably get the Teensy and audio board, and at least do the delay part of the tutorial yourself. An hour of fiddling with the real hardware will give you much better insight than weeks of questions here.

Regarding your questions that aren't in the video: for delayExt, the external chip(s) are used (either 1 on the audio board, or 6 if you make Frank's memoryboard), not internal RAM. But for internal RAM, there are functions to let you see how much memory the audio lib is using (www.pjrc.com/teensy/td_libs_AudioConnection.html). Yes, the TimerOne lib works together with audio, but no, you should not use it. Simpler code with elapsedMillis (www.pjrc.com/teensy/td_timing_elaspedMillis.html) in your loop would be easier.

jassing
02-17-2016, 12:43 AM
Thank you for your time! I found the workshop video & scheduled the video to download (I am on a metered internet connection with free download @ midnight) -- so I posted that before the video downloaded. It really cleared up a lot.

So for how much ram is used (combined total ram, internal/external) I will need to count time spent recording... I doubt it will really be an issue, as 10 seconds will pass quickly once it's turned on...

I'll skip using the timer then & just count milliseconds -- thank you.

I'm really excited! This is something new for me and I had almost given up hope that I could do it.... so this is awesome!

Thanks Paul ! (and everyone else who gave input -- it's all valuable & helpful)

Cheers
-josh

bdoan
03-18-2017, 03:42 AM
Any progress on being able to record continuously to an SD card?



I agree, Frank's memoryboard (https://github.com/FrankBoesing/memoryboard) with six 23LC1024 chips is probably the best solution. Maybe 9 seconds is enough for "what did he say?" ?

The memoryboard approach would be extremely easy too. Just run the audio into the delayExt object. Then use a mixer to route either the live or 9 second delayed signal to the output. Write a tiny program to change the mixer gains depending on the button. Very simple.

Doing this with a SD card might also be possible, but it'll be much harder. I believe it still should be possible....

The weak link will be the Arduino SD library. Several months ago I started an ambitious ground-up redesign of the SD library, to be usable from the main program and also interrupts, and to cache several sectors. However, that work is still at an early stage of development, with the main limitation being a lack of write support. Someday in a glorious but distant future, this work will lead to a far more capable SD library. But for now, you'll have to make do with the SD library we have. Or maybe bypass the library and FAT32 to directly access the SD card as raw sectors.

Because of the SD limitations, you won't be able to access the SD card from within the audio library. You'll need to use a pair of the queue objects to bring the streaming data in and out of your Arduino sketch. The good news is the queue objects automatically queue up arriving data if you (occasionally) need more time, and you certainly will on the occasions with the SD card takes longer to complete a write. The play queue also allows you to push in more than one packet of data quickly.

The SD library is faster if you always read 512 bytes at a time, of course aligned to the 512 byte sector boundaries. You'll want to structure your code to work with 512 byte chunks of data. Each of those corresponds nicely to 2 audio buffers.

You'll probably want to pre-allocate a huge 4 gigabyte file on the SD card. Perhaps you can arrange for the file to be contiguously allocated, which might let you completely bypass the filesystem to access it as raw sectors. But even if you go through the filesystem layer, creating the huge file in advance will save all the overhead of allocating space and writing changes to the FAT sectors.

How to both read and write from the file is a good question. Again, bypassing the filesystem (if the file isn't fragmented) and just reading and writing the raw sectors might be easiest. Using the SD library file operations, perhaps you can open the file twice, with one "File" for reading and and another for writing. If the file's size changes, that'll probably get terribly messed up. But maybe it'll work if the file's size and allocation doesn't change?

Anyway, as far as the audio library is concerned, this would involve a pair of the queue objects. You'd need to move the data between those and the media, which might not be too difficult, but it does mean writing code to rapidly move a lot of bytes around. That's quite a bit more complicated than using delayExt with the memoryboard and a trivial amount of code to reconfigure mixer gains to switch between the live and 9 second delayed signal.

PaulStoffregen
03-18-2017, 09:42 AM
Look at the example code, File > Examples > Audio > Recorder.