Pitch modification in praat - praat

I want to modify the pitch at two different parts of a wav file. To do that , i have the information of starting time and ending time from the corresponding textgrid file of the wav file. Is it possible to modify the pitch at two parts.

You can use a Manipulation object to make any changes you want to the original sound's pitch.
# Original sound made of three consecutive notes
snd[1] = Create Sound as pure tone: "A", 1, 0, 0.3, 44100, 220, 0.2, 0.01, 0.01
snd[2] = Create Sound as pure tone: "B", 1, 0, 0.3, 44100, 247, 0.2, 0.01, 0.01
snd[3] = Create Sound as pure tone: "C", 1, 0, 0.3, 44100, 277, 0.2, 0.01, 0.01
selectObject(snd[1], snd[2], snd[3])
sound = Concatenate
Rename: "original"
removeObject(snd[1], snd[2], snd[3])
selectObject(sound)
Play
# We will invert the pitch, so that the notes play in the opposite direction
manipulation = To Manipulation: 0.01, 200, 300
pitchtier = Extract pitch tier
# We copy it because we want to modify it, not create one from scratch
# and we want to be able to read the values of the original from somewhere
original = Copy: "old"
points = Get number of points
# This for loop looks at the values of the original pitch tier and writes them
# onto the new pitch tier
for p to points
selectObject(original)
f = Get value at index: points - p + 1
t = Get time from index: p
# If you uncomment the if block, the changes will only affect the first and last
# quarter of the sound
# if t < 0.25 or t > 0.75
selectObject(pitchtier)
Remove point: p
Add point: t, f
# endif
endfor
# We replace the pitch tier
selectObject(pitchtier, manipulation)
Replace pitch tier
# Resynthesize
selectObject(manipulation)
new_sound = Get resynthesis (overlap-add)
# And clean up
removeObject(original, pitchtier, manipulation)
selectObject(new_sound)
Rename: "modified"
Play
You change the pitch tier by adding points at different times with different pitch values (in Hertz), and when you do the resynthesis Praat will modify the original values so they match the ones you specified.
In your case, you can use the time values from the TextGrid to know when the modified PitchTier points need to be added and leave the rest alone. You can also manipulate duration like this.
In the example, the script changes the value of each of the points in the original pitch tier with the value of the points in the inverted order, so that the first point will have the value of the last one. The if block inside the for is one way of limiting those changes to a subset of the pitch tier, but how you do this will depend on the sort of changes you are trying to make.

Related

Is Pitch Shifting accurate in Praat?

I am trying to shift the pitch of a file in 20Hz, but when I do this in praat and get the mean pitch I never get the 20 Hz, just something similar.
For example I have a .85s file with "108.07459844192924 Hz (mean pitch in SELECTION)"; if I go to manipulation, get the pitch tier and shift it 20 Hz the result is a file 126.12524578822578 Hz (mean pitch in SELECTION)
I have already tried changing the time-step, minimum and maximum pitch when creating the manipulation object. That doesn't seem to be the problem
This is my script (I have tested doing it manually and have the same result):
Note: The array dur_files[] has 10 files with different lengths
for i from 0 to 10
for j from 0 to 10
selectObject: dur_files[i]
durat_mod = Get end time
manip = To Manipulation: 0.005, 10, 1000
selectObject: manip
pitch_tier = Extract pitch tier
selectObject: pitch_tier
Shift frequencies: 0, durat_mod, 3*(j-5), "Hertz"
plusObject: manip
Replace pitch tier
removeObject: pitch_tier
selectObject: manip
resynth = Get resynthesis (overlap-add)
removeObject: manip
selectObject: resynth
Rename: selected$ ("Sound") + "_pitch-" + string$(j-5))
lib_files[i,j] = selected()
lib_files_name$[i,j] = selected$()
endfor
endfor
Ok after almost a year I can answer my own question:
finding the pitch (F0) of a spech recording is not an straight forward thing, the pitch ony has sense in the voiced parts of the recording (vowels)
Praat in fact, makes the shift in pitch as intended, the measurement is the thing that can have an error

MATLAB image distinction/comparison

I have 1024 images, each of which has the size 150(y) x 270(x) which is stored as 3D array with the size of 150 x 270 x 1024
First 160 images are very similar to each other but not entirely identical;
however, after 160th image, pictures start to change drastically.
So, here is what I want to achieve:
I want to find the index of the image from which the images start to drastically change
I have tried to compare correlation between image #1 and other 1023 images by:
for ii = 1:1023
R(ii) = corr2(input(:,:,1),input(:,:,ii+1)); % input = 3D array (150 x 270 x 1024)
end
and see if there is any change in correlation coefficient at around 160th image, but wasn't successful.
What method can I use to detect changes in these images and to find the index at which my images start to change dramatically?
EDIT
following are some of the images I have (index in the title)
I guess the change is not as dramatic as I first described and when you look at image 160 and 161, the change is subtle but as it goes on, you can clearly see that the image definitely changes at the bottom part
These images are results of ultrasonic testing and wave propagation from PZT sensor starts at the bottom part of the image
Probably, this is not a full answer to your problem, but I hope I can give you some ideas to further work on. But before, I have to mention this: Image processing is two-dimensional signal processing! ;-)
After reading your question the 34th time (or so), I finally saw, that you're comparing "image" #1 with all others. Instead, you should compare neighbouring "images". I have put together the following script incorporating your approach of using corr2:
load('fullSet.mat');
%% Normalize values to [0, 1] with respect to whole volume.
%% Just for nicer image showing.
%minV = min(fullSet(:));
%fullSet = fullSet - minV;
%maxV = max(fullSet(:));
%fullSet = fullSet / maxV;
% Determine number of "images".
n = size(fullSet, 3);
% "Step size".
s = 1;
% Initialize R.
R = zeros(n-s, 1);
% Compute correlation coefficients.
for ii = 1:n-s
R(ii) = corr2(fullSet(:, :, ii), fullSet(:, :, ii + s));
end
% Show output.
figure(1);
subplot(3, 1, 1);
plot(1:n-s, R);
title('R');
xlim([0 n-s]);
subplot(3, 1, 2);
plot(1:n-s-1, diff(R, 1));
title('1st derivative of R');
xlim([0 n-s-1]);
subplot(3, 1, 3);
plot(1:n-s-2, diff(R, 2));
title('2nd derivative of R');
xlim([0 n-s-2]);
The "step size" defines which "image" should be compared to the current one, i.e. s = 1 is used to compare the current "image" with the next "image", s = 2 is used to compare the current "image" with the second-next "image", and so on.
The results for s = 1:
The results for s = 5:
The results for s = 10:
As you can see, there is a distinct change around [160, 200]. I also computed the 1st and 2nd derivatives, because here you can also see changes later in your "volume" - if this is of interest for you.
Please let me know, if you need further explanations on my script or if you need further help in general.

Plotting in IDL using POLYFILL

My supervisor has suggested the following code for extracting vertical slices from a set of 40 x 40 images and plotting them as a time series (24hrs), with images stored in an array 'images = FLTARR(no_images, 40,40)', and corresponding times in array UT=FLTARR(no_images):
PLOT, [0],[0], /NODATA, XRANGE=[0,24], XSTYLE, YRANGE=[-40,40], /YSTYLE
FOR i=0, no_images-1 DO BEGIN
FOR j=0, 39 DO BEGIN
POLYFILL, UT(i)+[0,0,1,1]*2/60.0, (j+[0,1,1,0])*2-40, COL=[work out what colour you want the pixel to be in terms of the value in images(i,20,j) ]
ENDFOR
ENDFOR
The images were taken at 2 minute intervals.
I understand what is being done here - essentially drawing small rectangles to represent the pixels in the images. My question is what should the COL argument be? Can someone give me an example? At the minute to test the code i've just put a fixed value (e.g. 255), which obviously just gives a block of the same color. How can i get different colours corresponding to the pixel values?
Just use:
max_value = max(ut[*, 20, *])
color=images[i, 20, j] / float(max_value) * 255
Make sure you are in indexed color, i.e., you have done:
device, decomposed=0
and used used LOADCT or TVLCT to load the color table you want to use.
You could also use new graphics if you have IDL 8.4+
no_images = 100
ut = FINDGEN(100)/100*24
img = bytscl(randomu(seed,no_images,40))
y = FINDGEN(40)
p = PLOT(ut, y, XSTYLE=1, YSTYLE=1, XRANGE=[0,24], YRANGE=[0,40], $
/NODATA, TITLE='My Data',XTITLE='X',YTITLE='Y')
i = IMAGE(img, ut, y, /OVERPLOT, RGB_TABLE=74, ASPECT_RATIO=0.5)
You can adjust the ASPECT_RATIO to make your image appear more or less square. And it's easy to change the RGB_TABLE to whatever one you'd like.

Efficient algorithm to fit a linear line along the upper boundary of data only

I'm currently trying to fit a linear line through a spread of scattered data in MATLAB. Now this is easy enough using the polyfit function where I can easily obtain my y= mx + c equation. However, I need to now fit a line along the upper boundary of my data, i.e., the top few data points. I know this description is vague, so lets assume that my scattered data will be in a shape of a cone, with its apex on the y-axis, and it spreads outwards and upwards in the +x and +y direction. I need to fit a best fit line on the 'upper edge of the cone' if you will.
I've developed an algorithm but it's extremely slow. It involves first fitting a line of best fit through ALL data, deleting all data points below this line of best fit, and iterating through until only 5% of the initial data points are left. The final best fit line will then reside close to the top edge of the cone. For 250 data points, this takes about 5s and with me dealing with more than a million data points, this algorithm is simply too inefficient.
I guess my question is: is there an algorithm to more efficiently achieve what I need? Or is there a way to sharpen up my code to eliminate unnecessary complexity?
Here is my code in MATLAB:
(As an example)
a = [4, 5, 1, 8, 1.6, 3, 8, 9.2]; %To be used as x-axis points
b = [45, 53, 12, 76, 25, 67, 75, 98]; %To be used as y-axis points
while prod(size(a)) > (0.05*prod(size(a))) %Iterative line fitting occurs until there are less than 5% of the data points left
lobf = polyfit(a,b,1); %Line of Best Fit for current data points
alen = length(a);
for aindex = alen:-1:1 %For loop to delete all points below line of best fit
ValLoBF = lobf(1)*a(aindex) + lobf(2)
if ValLoBF > b(aindex) %if LoBF is above current point...
a(aindex) = []; %delete x coordinate...
b(aindex) = []; %and delete its corresponding y coordinate
end
end
end
Well first of all your example code seems to be running indefinitely ;)
Some optimizations for your code:
a = [4, 5, 1, 8, 1.6, 3, 8, 9.2]; %To be used as x-axis points
b = [45, 53, 12, 76, 25, 67, 75, 98]; %To be used as y-axis points
n_init_a = length(a);
while length(a) > 0.05*n_init_a %Iterative line fitting occurs until there are less than 5% of the data points left
lobf = polyfit(a,b,1); % Line of Best Fit for current data points
% Delete data points below line using logical indexing
% First create values of the polyfit points using element-wise vector multiplication
temp = lobf(1)*a + lobf(2); % Containing all polyfit values
% Using logical indexing to discard all points below
a(b<temp)=[]; % First destroy a
b(b<temp)=[]; % Then b, very important!
end
Also you should try profiling your code by typing in the command window
profile viewer
and check what takes most time calculating your results. I suspect it is polyfit but that can't be sped up much probably.
What you are looking for is not line fitting. You are trying to find the convex hull of the points.
You should check out the function convhull. Once you find the hull, you can remove all of the points that aren't close to it, and fit each part independently to avoid the fact that the data is noisy.
Alternatively, you could render the points onto some pixel grid, and then do some kind of morphological operation, like imclose, and finish with Hough transform. Check out also this answer.

Punching a hole through a cylinder using Sketchup Ruby API

I'm writing a script to make a simple flute in SketchUp (free version, Mac). I want to make a tube and and then cylinders which poke through the tube, draw the intersection lines between the tube and the cylinders, then erase the cylinders, leaving circles to cut out of the tube.
This works if I do it with the mouse, but I found it difficult to be precise about placement and measurement with the mouse. So far, though, I haven't been able to make it work with a script. Currently I am stuck with it drawing incomplete circles on the tube, so I am unable to find the face and erase it. You should be able to run the following script in the ruby console and see what I mean. What am I doing wrong?
entities = Sketchup.active_model.entities
# make tube
tube = entities.add_group
tube_inner = tube.entities.add_circle Geom::Point3d.new(0,0,0), Geom::Vector3d.new(0,0,1), 5, 360
tube_outer = tube.entities.add_circle Geom::Point3d.new(0,0,0), Geom::Vector3d.new(0,0,1), 6, 360
cross_section_face = tube.entities.add_face tube_outer
inner_face = tube.entities.add_face tube_inner
tube.entities.erase_entities inner_face
cross_section_face.pushpull -10, false
# make a cylinder that punches through the wall
hole_punch = entities.add_group
hole_outer = hole_punch.entities.add_circle Geom::Point3d.new(0,0, 5), Geom::Vector3d.new(0,1,0), 3, 360
face = hole_punch.entities.add_face hole_outer
face.pushpull 10, false
# draw the intersection lines and erase the hole punch
entities.intersect_with true, hole_punch.transformation, tube, tube.transformation, true, hole_punch
hole_punch.erase!
Determining the correct faces to erase after intersecting can be very tricky.
But since you are working with cylinder shapes - which are solids - I would recommend you use the solid boolean operations that was introduced in SketchUp 8 Pro. You can use Group.subtract for instance. http://www.sketchup.com/intl/en/developer/docs/ourdoc/group#subtract
However, is you are not using SketchUp 8 Pro or newer then you won't have these methods available.
Alternative solution - avoiding the Solid Tools methods of the Pro version:
entities = Sketchup.active_model.entities
# (!) You created a circle with so many edges that at the scale
# you drew it they where pushing the boundary of how small
# units SketchUp can handle. (1/1000th inch).
# If you has Edge Outline style enabled you could see that
# not all edges where fully merged.
# I reduced the curve segments from 360 to 180.
# (Do you really need such a high mesh density anyway?)
# make tube
tube = entities.add_group
tube_inner = tube.entities.add_circle Geom::Point3d.new(0,0,0), Geom::Vector3d.new(0,0,1), 5, 180
tube_outer = tube.entities.add_circle Geom::Point3d.new(0,0,0), Geom::Vector3d.new(0,0,1), 6, 180
cross_section_face = tube.entities.add_face tube_outer
inner_face = tube.entities.add_face tube_inner
tube.entities.erase_entities inner_face
cross_section_face.pushpull -10, false
# make a cylinder that punches through the wall
hole_punch = entities.add_group
hole_outer = hole_punch.entities.add_circle Geom::Point3d.new(0,0, 5), Geom::Vector3d.new(0,1,0), 3, 180
face = hole_punch.entities.add_face hole_outer
face.pushpull 10, false
# draw the intersection lines and erase the hole punch
entities.intersect_with true, hole_punch.transformation, tube, tube.transformation, true, hole_punch
hole_punch.erase!
# Find all the edges that belong to the Circle elements drawn
# earlier (including the ones push-pulled).
# (Could also collect these earlier before intersecting by
# collecting all non-smooth edges.)
circles = tube.entities.grep(Sketchup::Edge).select { |e| e.curve }.uniq
# Then we pick out all the faces that isn't connected to these edges and erase them.
new_faces = tube.entities.grep(Sketchup::Face).select { |f| (f.edges & circles).empty? }
entities.erase_entities( new_faces )
If you really want 360 segment circles you can scale the content of the group up - while you scale the group instance down. That way the group definition is at a much bigger scale. (See this article on instances and definitions in SketchUp: http://www.thomthom.net/thoughts/2012/02/definitions-and-instances-in-sketchup/)
Also, if you want faces to fill the hole between the inner and outer skin you need to intersect that part as well.
Note about the Entities.intersect_with description - the current docs doesn't explain well all the arguments. There are two entities arguments.
The first one should be a Sketchup::Entities object where the intersected objects should appear. (I'm a bit surprised it worked by feeding it a Sketchup::Group object.)
The second should not be Sketchup::Entities - that will fail. It must be an Sketchup:Entity or array of Sketchup:Entity objects.

Resources