There are pitch and duration and sample rate fs where "pitch" is the vector of note pitch in semitones (with 0 indicating silence), "duration" is the vector of note duration in seconds, "fs" is the sample rate of the output wave signals for playback.
pitch= [55 55 55 55 57 55 0 57 60 0 ];
duration=[23 23 23 23 23 35 9 23 69 18 ]/64;
fs=16000;
I want to use above info to return audio signal in MATLAB.
Can somebody teach me?
THX
This requires some thought and might just take some time to write down before everything is working.
Personally, I'd split the task up into multiple functions which in my mind would involve:
1. Semitone to frequency
2. Time to sample number
3. Frequency and sample number to output waveform
And if possible you should add another array which involves level for further progress later on/ helps simplify the problem into stages.
As im not sure which semitone scaling you are using you will have to confirm this for yourself but you will need some sort of converter/look up table that does something like (formulas according to Physics of Music website):
function [frequency] = semitone2frequency(semitone)
%Your input is how many semitones ABOVE middle C your note is
frequency = 440*((2^(1/12))^semitone); % where 440 Hz is middle C
end
This is based on an equal tempered scale. Now you know the frequency of your notes you could generate their sound, but wait theres more....
Now you can calculate the time of each sound in samples by writing another function...
function [nSamples] = time2samples(time, Fs)
dt = 1/Fs;
nSamples = time*dt;
end
Now that you have both of these values you can generate your audio signal!
frequency = semitone2frequency(55); %55 semitones above middle C
nSamples = time2samples(2,16000); %How many samples does it need to play 2 seconds
%Generate time array from 0 to how long you want the sound to be
time = 0:1:nSamples; %Starts at 0 increases by 1 sample each time up until 2 seconds worth of samples
%Create your output waveform!
outputAudio = sin(2*pi*frequency.*time);
This will create an array which you could play that will sound a note 55 semitones greater than middle C (not sure what note that actually is) for 2 seconds. Listen to it by using:
sound(outputAudio, 16000);
You can build on this to create multiple sounds one after the other (I would recommend creating one master function that lets you pass all arrays in and outputs one audio waveform), but this should be enough to create certain semitones for given durations!
P.s. To make the level 0 at any time simply multiply your outputAudio variable by 0
outputAudio = outputAudio.*0; %The . in .* is important!
Or for further control multiply it by any level between 0 and 1 for complete volume control.
I hope this is enough! good luck.
Related
I need to run a simulation with sample time of
tsample = 0.01 ; % seconds
I have a table such as below
I need to resample each column in input table such that value of the input Time vector gets equally spaced based on tsample values.
For the [Time] column I achieved this by following code
simTime = max(tests.(test_names{i}).Times); % Seconds
% Interpolate the time and frequency values as per sample time
numSteps = simTime/tsample;
time = tsample * [0:(numSteps-1)]';
What I need to do now is resize the frequency (f) values such that it shall be filled with previous values until a new value is found in column;
Time
f
0
50
....
50
4.99
50
5.00
49.65
....
49.65
19.99
49.65
20.00
49.80
I am confused whether I should use fillmissing or resample or interp1.
The examples I am following for these seem kind of different than what I wish to achieve here.
Any help would be really appreciated.
Thank you.
Ok,
I tried experimenting with more examples for interp1 and this solved my issue.
freq = interp1(tests.Times, tests.fHz, time, 'previous');
I was earlier unaware of the 'previous' option
Should have searched the documentation more extensively.
I'm attempting to model fMRI data so I can check the efficacy of an experimental design. I have been following a couple of tutorials and have a question.
I first need to model the BOLD response by convolving a stimulus input time series with a canonical haemodynamic response function (HRF). The first tutorial I checked said that one can make an HRF that is of any amplitude as long as the 'shape' of the HRF is correct so they created the following HRF in matlab:
hrf = [ 0 0 1 5 8 9.2 9 7 4 2 0 -1 -1 -0.8 -0.7 -0.5 -0.3 -0.1 0 ]
And then convolved the HRF with the stimulus by just using 'conv' so:
hrf_convolved_with_stim_time_series = conv(input,hrf);
This is very straight forward but I want my model to eventually be as accurate as possible so I checked a more advanced tutorial and they did the following. First they created a vector of 20 timepoints then used the 'gampdf' function to create the HRF.
t = 1:1:20; % MEASUREMENTS
h = gampdf(t,6) + -.5*gampdf(t,10); % HRF MODEL
h = h/max(h); % SCALE HRF TO HAVE MAX AMPLITUDE OF 1
Is there a benefit to doing it this way over the simpler one? I suppose I have 3 specific questions.
The 'gampdf' help page is super short and only says the '6' and '10' in each function call represents 'A' which is a 'shape' parameter. What does this mean? It gives no other information. Why is it 6 in the first call and 10 in the second?
This question is directly related to the above one. This code is written for a situation where there is a TR = 1 and the stimulus is very short (like 1s). In my situation my TR = 2 and my stimulus is quite long (12s). I tried to adapt the above code to make a working HRF for my situation by doing the following:
t = 1:2:40; % 2s timestep with the 40 to try to equate total time to above
h = gampdf(t,6) + -.5*gampdf(t,10); % HRF MODEL
h = h/max(h); % SCALE HRF TO HAVE MAX AMPLITUDE OF 1
Because I have no idea what the 'gampdf' parameters mean (or what that line does, in all actuality) I'm not sure this gives me what I'm looking for. I essentially get out 20 values where 1-14 have SOME numeric value in them but 15-20 are all 0. I'm assuming there will be a response during the entire 12s stimulus period (first 6 TRs so values 1-6) with the appropriate rectification which could be the rest of the values but I'm not sure.
Final question. The other code does not 'scale' the HRF to have an amplitude of 1. Will that matter, ultimately?
The canonical HRF you choose is dependent upon where in the brain the BOLD signal is coming from. It would be inappropriate to choose just any HRF. Your best source of a model is going to come from a lit review. I've linked a paper discussing the merits of multiple HRF models. The methods section brings up some salient points.
I have a 164 x 246 matrix called M. M is data for time series containing 246 time points of 164 brain regions. I want to work on only specific blocks of the time series, not the whole thing. To do so, I created a vector called onsets containing the time onset of each block.
onsets = [7;37;82;112;145;175;190;220];
In this example, there are 8 blocks total (though this number can vary), each blocks containing 9 time points. So for instance, the first block would contain time point 7, 8, 9,..., 15; the second block would contain time point 37, 38, 39,..., 45. I would like to extract the time points for these 8 blocks from M and concatenate 8 these blocks. Thus, the output should be a 164 x 72 matrix (i.e., 164 regions, 8 blocks x 9 time points/per block).
This seems like a very simple indexing problem but I'm struggling to do this efficiently. I've tried indexing each block in M (for intance, vertcat(M(onsets(1,1):onsets(1,1)+8,:));) then use vertcat but this seems very clumsy. Can anyone help?
Try this:
% create sample data
M = rand(164,246);
% create index vector
idx = false(1,size(M,2));
onsets = [7;37;82;112;145;175;190;220];
for i=1:numel(onsets)
idx(onsets(i):onsets(i)+8) = true;
end
% create output matrix
MM = M(:,idx);
You seem to have switched the dimensions somehow, i.e. you try to operate on the rows of M whilst according to your description you need to operate on the columns. Hope this helps.
I'm trying to simulate an optical network algorithm in MATLAB for a homework project. Most of it is already done, but I have an issue with the diagrams I'm getting.
In the simulation I'm generating exponential traffic, however, for low lambda values (0.1) I'm getting very high packet drop rates (99%). I wrote a sample here which is very close to the testbench I'm running on my simulator.
% Run the simulation 10 times, with different lambda values
l = [1 2 3 4 5 6 7 8 9 10];
for i=l(1):l(end)
X = rand();
% In the 'real' simulation the following line defines the time
% when the next packet generation event will occur. Suppose that
% i is the current time
t_poiss = i + ceil((-log(X)/(i/10)));
distr(i)=t_poiss;
end
figure, plot(distr)
axis square
grid on;
title('Exponential test:')
The resulting image is
The diagram I'm getting in this sample is IDENTICAL to the diagram I'm getting for the drop rate/λ. So I would like to ask if I'm doing something wrong or if I miss something? Is this the right thing to expect?
So the problem is coming from might be a numerical problem. Since you are generating a random number for X, the number might be incredibly small - say, close to zero. If you have a number close to zero numerically, log(X) is going to be HUGE. So your calculation of t_poiss will be huge. I would suggest doing something like X = rand() + 1 to make sure that X is never close to zero.
I have an EMG signal of a subject walking on a treadmill.
We used footswitches to be able to see when the subject is placing his foot, so we can see how many periods (steps) there are in time.
We would like to cut the signal in periods (steps) and get one average signal (100% step cycle).
I tried the reshape function but it does not work
when I count 38 steps:
nwaves = 38;
sig2 = reshape(sig,[numel(sig)/nwaves nwaves])';
avgSig = mean(sig2,1);
plot(avgSig);
the error displayed is this: Size arguments must be real integers.
Can anyone help me with this? Thanks!
First of all, reshaping the array is a bad approach to the problem. In real world one cannot assume that the person on the treadmill will step rhythmically with millisecond-precision (i.e. for the same amount of samples).
A more realistic approach is to use the footswitch signal: assume is really a switch on a single foot (1=foot on, 0=foot off), and its actions are filtered to avoid noise (Schmidt trigger, for example), you can get the samples index when the foot is removed from the treadmill with:
foot_off = find(diff(footswitch) < 0);
then you can transform your signal in a cell array (variable lengths) of vectors of data between consecutive steps:
step_len = diff([0, foot_off, numel(footswitch)]);
sig2 = mat2cell(sig(:), step_len, 1);
The problem now is you can't apply mean() to the signal slices in order to get an "average step": you must process each step first, then average the results.
It's probably because numel(sig)/nwaves isn't an integer. You need to round it to the nearest integer with round(numel(sig)/nwaves).
EDIT based on comments:
Your problem is you can't divide 51116 by 38 (it's 1345.2), so you can't reshape your signal in chunks of 38 long. You need a signal whose length is exactly a multiple of 38 if you want to be able to reshape it in chunks of 38. Either that, or remove the last (or first) 6 values from your signal to have an exact multiple of 38 (1345 * 38 = 51110):
nwaves = 38;
n_chunks = round(numel(sig)/nwaves);
max_sig_length = n_chunks * nwaves;
sig2 = reshape(sig(1:max_sig_length),[n_chunks nwaves])';
avgSig = mean(sig2,1);
plot(avgSig);