Matlab real time audio processing - matlab

I'm trying to record my microphone input and process it at the same time.
I tried with a loop with this inside:
recordblocking(recorder, 1);
y = getaudiodata(recorder);
% any processing on y
But while I'm doing something with y, I'm losing information since not recording continuously.
Is there something I could do to continuously record sound coming in my microphone, store it in some kind of buffer, and process chunks of it at the same time?
A delay isn't a problem, but I really need the recording and processing done simultaneously.
Thanks in advance for any help.

I think that you should use Stream processing like this:
% Visualization of audio spectrum frame by frame
Microphone = dsp.AudioRecorder;
Speaker = dsp.AudioPlayer;
SpecAnalyzer = dsp.SpectrumAnalyzer;
tic;
while(toc<30)
audio = step(Microphone);
step(SpecAnalyzer,audio);
step(Speaker, audio);
end
you can find more information here and also in this presentation

You can try the block processing framework in LTFAT
http://ltfat.github.io/doc/demos/demo_blockproc_basicloop_code.html
Edit:
This is the main gist of the code:
% Basic Control pannel (Java object)
p = blockpanel({
{'GdB','Gain',-20,20,0,21},...
});
% Setup blocktream
fs = block('playrec','loadind',p);
% Set buffer length to 30 ms
L = floor(30e-3*fs);
flag = 1;
%Loop until end of the stream (flag) and until panel is opened
while flag && p.flag
gain = blockpanelget(p,'GdB');
gain = 10^(gain/20);
% Read the block
[f,flag] = blockread(L);
% Play the block and do the processing
blockplay(f*gain);
end
blockdone(p);
Note that it is possible to specify input and output devices and their channels by passing additional arguments to the block function. List of available audio devices can be obtained by calling blockdevices.

Related

How can play an audio file with plotting a diagram simultaneously in matlab?

I would like to play an audio file Meanwhile plotting and updating a diagram. However, my audio file is interrupted. I would like to play audio file smoothly in background and update the figure at the same time.
for i=1:10
player = audioplayer(audio, Fs);
play(player);
scatter(x(i),y(i),'r.')
end
Your problem is that play is an asynchronous call: it means the program execution continues immediately after the call to 'play(player)'.
If you intend to play different files at each iteration, try waiting till the current file finishes, you can use something like:
while player.isplaying
pause(0.001)
end
If you meant to play one signal and change the plots, move the play(player) outside of the for loop, and add some delay between each plotting point for example with your code:
player = audioplayer(audio, Fs);
play(player);
for i=1:10
scatter(x(i),y(i),'r.')
pause(0.1)
end
Example for one signal being played and plot being updated:
Build a chirp signal:
Fs = 16e3;
T = 10;
t = 0:1/Fs:T;
f0 = 100;
phi = 2*pi*t.^2*f0;
sig = 0.1*sin(phi);
% Start playing the sound:
player = audioplayer(sig,Fs);
play(player);
% Plotting stuff:
dPhi = gradient(phi)*Fs;
figure;
numPlots = 20;
N = numel(t);
for n = 1 : numPlots
pause(T/numPlots)
ind = 1:N/numPlots*n;
plot(t(ind), dPhi(ind))
end
In general when plotting 'real-time' it is better to use tic-toc to figure current time compared to the time the audio started playing.
Also to improve performance it is better to set the xdata & ydata of the plots instead of re-plotting it every time as this action is much faster (doesn't update all other properties of the axes).
You can look at an old script I once shared to do 'real-time' plotting:
https://www.mathworks.com/matlabcentral/fileexchange/14397-real-time-scope-display--simple-script-

Use audioread or equivalent to play audio in a specific timestamp

I am using audioread to play audio, now I would like play the track in different timestamps. What I have so far is:
[testSound,Fs] = audioread('test.wav');
sound(testSound,Fs);
Is it possible to somehow specify that the audio-track shall start at for example second 5? To be more specific, my audio sample test.wav is 45 second long, instead of playing the sound from the beginning, I would like to define where it should start playing.
Any help is much appreciated!
You can extract out a portion of the signal so that you're starting at the 5 second mark, then play it. Simply put, you'd start sampling at 5 times the sampling rate as the starting index all the way to the end then play the sound:
[testSound,Fs] = audioread('test.wav'); % From your code
beginSecond = 5; % Define where you want to start playing
beginIndex = floor(beginSecond*Fs); % Find beginning index of where to sample
soundExtract = testSound(beginIndex:end, :); % Extract the signal
sound(soundExtract, Fs); % Play the sound
Alternatively, since you're using audioread, you can actually specify where to start sampling the sound. You'd use the same logic above and specify the beginning and end of where to sample the sound in terms of samples. However, you'd need to know what the sampling rate is first so you'd have to call audioread twice to get the sampling rate, then finally the signal itself:
beginSecond = 5; % Define where you want to start playing
[~, Fs] = audioread('test.wav'); % Get sampling rate
beginIndex = floor(beginSecond*Fs); % Find beginning index of where to sample
[soundExtract, ~] = audioread('test.wav', [beginIndex inf]); % Extract out the signal from the starting point to the end of the file
sound(soundExtract, Fs); % Play the sound

Force a Specific Camera Aquisition Framerate in a realtime Matlab Loop

I have a function running in real time controlling hardware timing, etc. I want to be able to record video as well, so I've created a global video object in matlab, and set the triggering to manual. Right now, I have it so that each iteration of the realtime loop I record a frame and write it to disk. I'm changing it so that Ill record to memory till I hit some limit, and then writing to disk. However, I'd like to guarantee no matter how fast the real time loop is running, I only capture 15 frames per second.
Thinking about though, how can I make it so that I capture the 15 frames not so dramatically close to each other? If the real time loop is running lightning fast, the 15 frames will just be gathered at the "beginning" and capture almost no change that has occurred during that second. In other words, the faster real time loop is, the more my sampling will act like 1 frame per second (which has 14 other copies made).
For example,
% Main File
function start()
global vid;
global myLogger;
vid = videoinput('winvideo', 1, 'MJPG_160x120');
src = getselectedsource(vid);
triggerconfig(vid, 'manual');
vid.FramesPerTrigger = 1;
vid.LoggingMode = 'disk&memory';
imaqmem(512000000); % 512 MB
myLogger = VideoWriter('C:\Users\myname\Desktop\output.avi', 'Motion JPEG AVI');
myLogger.Quality = 50;
myLogger.FrameRate = 15;
vid.DiskLogger = myLogger;
src.FrameRate = '15.0000';
vid.ReturnedColorspace = 'grayscale';
start(vid);
open(myLogger);
initiateFastLoop();
close(myLogger);
stop(vid);
end
The real time piece:
function initiateFastLoop
global vid;
global myLogger;
while(flag)
% perform lightning fast stuff
frame = getsnapshot(vid);
writeVideo(myLogger, frame);
end
end
The video generated is much higher framerate, and I don't want to capture a frame every single time realtime loop runs, and I don't want to set a simple upper limit because of the problem described above. Any help would be great!

Can you synchronize the data acquisition toolbox and the image acquisition toolbox of Matlab?

I'd like to simultaneously get data from a camera (i.e. an image) and an analog voltage using matlab. For the camera I use the imaq toolbox, for reading the voltage I use the daq toolbox (reading NI-USB device), with a following code:
clear all
% Prepare camera
vid = videoinput('gentl', 1, 'Mono8');
src = getselectedsource(vid);
vid.FramesPerTrigger = 1;
vid.TriggerRepeat = Inf;
triggerconfig(vid, 'hardware', 'DeviceSpecific', 'DeviceSpecific');
src.FrameStartTriggerMode = 'On';
src.FrameStartTriggerActivation = 'RisingEdge';
% prepare DAQ
s=daq.createSession('ni');
s.addAnalogInputChannel('Dev1','ai1','Voltage');
fid = fopen('log.txt','w');
lh = s.addlistener('DataAvailable',#(src,event)SaveData(fid,event));
s.IsContinuous = true;
% Take data
s.startBackground();
start(vid)
N=10;
for ii=1:N
im(:,:,ii)=getsnapshot(vid);
end
% end code
delete(lh );
fclose('all');
stop(vid)
delete(vid)
where the function SaveData is:
function SaveData(fid,event)
time = event.TimeStamps;
data = event.Data;
fprintf(fid, '%f,%f\n ', [time data]);
end
I do get images and a log.txt file with the daq trace (time and data), but how can I use the external triggering (that trigger the camera) or some other clock to synchronize the two?
For this example, the daq reads the camera triggering TTL signal (# 50 Hz), so I want to assign each TTL pulse to an image.
Addendum:
I've been searching and have found a few discussions (like this one) on the subject, and read the examples that are found in the Mathworks website, but haven't found an answer. The documentation shows how to Start a Multi-Trigger Acquisition on an External Event, but the acquisition discussed is only relevant for the DAQ based input, not a camera based input (it is also working in the foreground).
This will not entirely solve your problem, but it might be good enough. Since the synchronization signal you are after in at 50 Hz, you can use clock in order to create time stamps for both types of your data (camera image and analog voltage). Since the function clock takes practically no time (i.e. below 1e-7 sec), you can try edit to your SaveData function accordingly:
fprintf(fid, '%f,%f\n ', [clock time data]);
And in the for loop add:
timestamp(i,:)=clock;
Can you use the sync to trigger the AD board? From the USB-6009 manual...
Using PFI 0 as a Digital Trigger--
When an analog input task is defined, you can configure PFI 0 as a digital trigger input. When the digital trigger is enabled, the AI task waits for a rising or falling edge on PFI 0 before starting the acquisition. To use AI Start Trigger (ai/StartTrigger) with a digital source, specify PFI 0 as the source and select a rising or falling edge.
My experience suggests that delay between trigger and AQ is very short
I'm sorry I use Python or C for this, so I can't give you MatLab code, but you want to look at functions like.
/* Select trigger source */
Select_Signal(deviceNumber, ND_IN_START_TRIGGER, ND_PFI_0, ND_HIGH_TO_LOW);
/* specify that a start trigger is to be used */
DAQ_Config(deviceNumber, startTrig, extConv); // set startTrig = 1
/* start the acquisition */
DAQ_Start(deviceNumber, …)
If you want to take this route you could get more ideas from:
http://www.ni.com/white-paper/4326/en
Hope this helps,
Carl
This is yet no complete solution, but some thoughts that might be useful.
I do get images and a log.txt file with the daq trace (time and data), but how can I use the external triggering (that trigger the camera) or some other clock to synchronize the two?
Can you think of a way to calibrate your setup? I.e. modify your experiment and create a distinct event in both your image stream and voltage measurements, which can be used for synchronization? Just like this ...

Continuous Video Recording in Matlab, Saving/Restarting On a Memory Cap, Ending on a Flag

I would like to record a continuous video in Matlab until some other flag changes, allowing matlab to continue performing other tasks during video acquisition (like deciding whether or not the flag should be set). Since these recordings could last upwards of 3 hours, perhaps closing the recording every hour, writing to a file video_1, then recording for another hour and dumping to video_2, etc for as long as the flag isn't set. However, from what I've seen using Matlab's Image Processing Toolbox, you have to specify some kind of number of frames to capture, or frames per trigger, etc. I'm not really too sure how to proceed.
Some simple code to record video I have is:
% create video obj
video = videoinput('winvideo',1);
% create writer obj
writerObj = VideoWriter('output.avi');
% set video properties
video.LoggingMode = 'disk';
video.DiskLogger = writerObj;
% start recording video
start(video);
% wait
wait(video, inf)
% save video
close(video.DiskLogger);
delete(video);
clear video;
However, the output video is only .3 seconds long. I've followed the following tutorial to get a 30 second recording down to a 3 second video available here but I can't figure out how to make it go on continuously.
Any help would be appreciated!
aviObject = avifile('myVideo.avi'); % Create a new AVI file
for iFrame = 1:100 % Capture 100 frames
% ...
% You would capture a single image I from your webcam here
% ...
F = im2frame(I); % Convert I to a movie frame
aviObject = addframe(aviObject,F); % Add the frame to the AVI file
end
aviObject = close(aviObject); % Close the AVI file
source: How do I record video from a webcam in MATLAB?