Audio player - sharing data between callbacks - matlab

I already asked this question to no avail. I couldn't solve the problem. I am trying again maybe someone can help!
I have 2 buttons, Play and Stop. I would have the path of an audio track at hand and want the audio to play when the user clicks on play and stop when the user clicks on stop. The only problem is that once the callback function of play exits, the variable holding the info about the player is emptied, and hence the track does not play. I needed some method to share data between callback functions..
I tried using global variables to no avail..
then I looked at this and I tried more or less each and every mentioned method: http://www.mathworks.com/help/matlab/creating_guis/share-data-among-callbacks.html#bt9p4qp
Let's take for instance this method:
In the play callback button:
[Y, Fs] = audioread(path);
player = audioplayer(Y,Fs);
hObject.UserData = player;
play(player);
In the stop callback button:
h = findobj('Tag','Play');
player = h.UserData;
stop(player);
On hObject.UserData = player; I am getting this warning when clicking on the play button:
Warning: Struct field assignment overwrites a value with class "double". See MATLAB R14SP2 Release Notes,
Assigning Nonstructure Variables As Structures Displays Warning, for details.
The solution I need would let me keep using the rest of the program while the music is playing, stop the audio whenever I want, and the program must obviously keep working well after that.
Any ideas guys? any help would be truly appreciated!
Thanks in advance!

I'm not shure whether the following works:
hObject.UserData = player;
I would (as you have already found out) use a global variable. I didn't test this solution, but it should work and shows how to use global variables in combination with a GUI correct. Please correct me if you found a mistake.
% --- Executes just before GUI is made visible.
function GUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargi
% Create a global player variable
global player;
player = audioplayer(Y,Fs);; % initialize player
% --- Outputs from this function are returned to the command line.
function pushbutton_off(hObject, eventdata, handles)
global player; % tell matlab player is global
play(player)
% --- Outputs from this function are returned to the command line.
function pushbutton_on(hObject, eventdata, handles)
global player;
stop(player);

Related

How can I program the cpu to randomly press buttons?

I am creating a game in matlab app designer in which a player plays against the computer opponent. I want to code the CPU to press a button at random when it is its turn. For example, in TicTacToe the player plays against another player but in this case, the opponent is the CPU. The CPU is able to click buttons at random for example if there are 9 buttons it will press on any of those 9 randomly providing it has not been pressed already. I am not sure how to program this any help would be highly appreciated.
I have tried to use the callback function but do not know how to program the cpu to randomly press buttons.
On second thought, this is not as simple as triggering the callback function, because you have to let the AI know when to "press" the button also. So, the part about notifying the AI should be in the callback function as well:
function ButtonPushed(app, event)
% Get the button that triggered the callback function
btn = event.Source;
btn.Text = 'X';
btn.Enable = 'off';
% Now, notify the AI to make its move
AI_btn = app.Button_(randi(9));
% Obviously there are better ways to do this
% I will leave it for your own improvisation
while ~isequal(AI_btn.Enable, 'on')
% If the button is already pressed...
AI_btn = app.Button_(randi(9));
end
AI_btn.Text = 'X';
AI_btn.Enable = 'off';
end

Matlab: How to call play(recorder) from GUI

If entered at the command line in Matlab 2016, the following lines will create an audiorecorder object, start it recording, stop it recording, write the recorded samples to a wav, and play the samples from the recorder object (i.e., not from the newly written wav file):
rec = audiorecorder(44100, 16, 1);
record(rec); % User speaks now
stop(rec);
audiowrite('foo.wav', getaudiodata(rec), 44100);
play(rec);
I am trying to partition this into a three button GUI (created with GUIDE) with the following functionality:
Start button, which starts a created recorder
Stop button, which stops the recorder AND saves the wav file
Playback button, which plays back the samples from the recorder
(The idea is to be able to record small samples of text, quickly listen for a first pass of quality, and decide whether or not to record over or to advance to the next sample.
Create the recorder object (among other things) in the initial setup for the GUI:
function ReadingScript_OpeningFcn(hObject, eventdata, handles, varargin)
recorder = audiorecorder(Fs, nbits, nChannels);
Start the recorder object:
function startRecord_Callback(hObject, eventdata, handles)
global recorder
set(handles.status,'String', 'Recording');
record(recorder);
Stop the recorder object AND save samples to a file:
function stopRecord_Callback(hObject, eventdata, handles)
global recorder
global wavname
stop(recorder);
audiowrite(wavname, getaudiodata(recorder), 44100)
Play the samples back:
function PlayBack_Callback(hObject, eventdata, handles)
global recorder
play(recorder)
Everything here works except playing the samples back. Samples are recorded into the recorder, which starts and stops with the correct button presses, and a wav file is saved. But the samples will not play. I even know the playback button is firing because of the intentional missing semicolon, which causes the details of the recorder object to be printed to screen, which also verifies that samples are still in it.
What exactly am I missing, that will make the audio play?
There seems to be a quirk of the audiorecorder that means it won't play within a GUI.
In order to get it working I needed to use playblocking with an audioplayer object as shown below
global recorder
disp('playing');
player = audioplayer(getaudiodata(recorder),44100,16);
playblocking(player);

MATLAB - Detect double mouse click on figure

I'm using impoly to allow the user to edit a polygon on a figure. Right now, I'm using pause() to detect when user is done, but I'd rather if it were a double-mouse click (similar to what roipoly does).
I cannot use roipoly though, since it does not allow an initial polygon be plotted, which is necessary.
Any ideas on how to get that?
The impoly tool appears to modify the WindowButtonDownFcn, WindowButtonMotionFcn, WindowButtonUpFcn, WindowKeyPressFcn, and WindowKeyReleaseFcn callbacks of the figure window. I had originally thought that you couldn't modify any of these because they would be overwritten by the callback function used by impoly for its functionality. However, it turns out that they can still be invoked properly. This gives you a few more options:
Modify WindowButtonDownFcn:
To add the ability to detect a double-click, you would have to use the WindowButtonDownFcn callback. For example:
set(gcf, 'WindowButtonDownFcn', #double_click_fcn);
h = impoly();
% Define this function somewhere (nested, local, etc.):
function double_click_fcn(hSource, ~)
if strcmp(get(hSource, 'SelectionType'), 'open')
% Advance to next frame
end
end
Modify WindowScrollWheelFcn:
Whenever I create a GUI where I have to scroll through a number of time points/plots/images, I like to use the WindowScrollWheelFcn callback to advance (scroll up) or rewind (scroll down) the data. You could use it to scroll from frame to frame, displaying whatever polygon has already been drawn (if there is one) or allowing the user to create a new one. For example:
set(gcf, 'WindowScrollWheelFcn', #scroll_fcn)
h = impoly();
% Define this function somewhere (nested, local, etc.):
function scroll_fcn(~, eventData)
if (eventData.VerticalScrollCount < 0)
% Mouse has been scrolled up; move to next frame
else
% Mouse has been scrolled down; move to previous frame
end
end
Modify WindowKeyPressFcn
You could also use the WindowKeyPressFcn callback to allow you to advance frames using keyboard buttons, like the left and right arrow keys. For example:
set(gcf, 'WindowKeyPressFcn', #keypress_fcn)
h = impoly();
% Define this function somewhere (nested, local, etc.):
function keypress_fcn(~, eventData)
switch eventData.Key
case 'rightarrow'
% Right arrow pressed; move to next frame
case 'leftarrow'
% Left arrow pressed; move to previous frame
end
end
For more information on creating all these callbacks, see here.

Real time audio matlab. Loop while answering to gui calls

I'm doing a simple GUI in matlab using guide, where I have some sliders to select a frequency or many which then get plotted and played through the speakers. I'm learning real-time sound right now so I thought it'd be neat to incorporate it into the application. I right now have a button that plays the sinusoidal waves for 10 seconds when I press it, but I want a checkbox that disables the button when checked and immediately starts playing the sound continuously until the checkbutton is unchecked again.
I can't really get my head around how to do this in Matlab since I heard Matlab is inherently single threaded. And how to do it right with the GUI and everything since I suspect GUI creation is something you think you do right, but you miss some kind of detail and it only works in some situations.
What I think would be the easy way would be to have the check of the checkbox set the 'Enable' property of the Play button to false, and start an infinite loop that plays it from the real time system object I create. When I however uncheck the checkbox, it should set a flag or something to false and enable the Play button again. Could someone point me to if this is the right approach? How do I make the application listen to clicks on the check box while simultanously being in an infinite loop that processes and plays sound? The simultanous loop should be sensitive to changes in the sliders determining the frequencies and those frequencies are also stored in the handles variable.
Mockup code:
function playbutton_Callback(hObject, eventdata, handles)
freqs = [handles.freq1, handles.freq2, handles.freq3]
hightensecy = sinewave(handles.hightensecx, freqs); %creates a sinewave consisting of the three frequencies. hightensecx is a time vector of ten seconds with a high sample rate.
sound(hightensecy, handles.highsr);
figure;
plot(handles.hightensecx,hightensecy);
function y = sinewave(x, freqs)
% x in sec
y(:,1:size(freqs,2)) = sin(2*pi*x*freqs);
y=sum(y,2)/size(freqs,2);
end
% --- Other code to make the sliders store their values in handles.freq1, handles.freq2... ---
function continuousbox_Callback(hObject, eventdata, handles)
selected = get(hObject,'Value');
if(selected)
set(handles.playbutton, 'Enable', 'off');
startsound(handles);
else
set(handles.playbutton, 'Enable', 'on');
stopsound();
end
% Plays sound continuously
function startsound(handles)
%%Initialization
SamplesPerFrame = 1024;
Fs = handles.highsr;
Player = dsp.AudioPlayer('SampleRate', Fs);
%%Stream
tic
while(1)
%TODO Read in a new 1024 bytes chunk and make sure it has the same
%characteristics as sinewave(x, freqs)
step(Player, outsound)
end
%Stops the continuously played sound
function stopsound()
%TODO Somehow stop the loop inside startsound(handles)
If it is possible, it would be good if the resulting startsound function plays a sound that sounds exactly like the playbutton callback, only indefinitely. I'm also not sure how to handle phase issues that might occur in the real time loop. Should I use a time counter that tics away and calculates the current 1024 chunk's y-value and in that case, should I just use the time distance from tic, or increase it with 1024/sample rate seconds per time? Thanks in advance.

Changing the Value of a Variable While the Code is Running

I'm writing a code that will take the location of the cursor and output a sound signal. But here's the catch: There is already a sin function playing in the background, the mouse click will merely change the x and y values of this sound. Here is what I came up with so far:
clear all
clc
k = 1:1200;
k = k/5000;
x=1;
y=1;
while i<10;
[x,y]=ginput(1)
vib= 0.5*sin(2*pi*y*k);
note=sin(pi*x*k*440);
ses = note+vib;
sound (ses);
end
As you can see my code just plays a sin function but it is discrete. Can someone please help me? I researched handles and callbacks but I just can't get it in my head. The explanations that I find in the net are too complicated for me to understand.
sound (ses); just takes the variable "ses" and plays. While it plays you can not interfere in the data in the way you think. You can observe the change in the next sound() function call.
If you want to continously play a waveform you can look at here:
Matlab: How to get the current mouse position on a click by using callbacks