Praat scripting: How to extract max of pitch for every syllable? - praat

I want to extract the maximum pitch for every syllable.
I have a piece of code, but it throws an error:
writeInfoLine: ""
selectObject: "TextGrid example", "Pitch example"
# syllable tier is 1
number = Get number of intervals: 1
for i from 1 to number
name$ = Get label of interval: 1, i
start_time = Get start time of interval: 1, i
end_time = Get end time of interval: 1, i
max_pitch = Get maximum: start_time, end_time, "Hertz", "Parabolic"
appendInfoLine: name$, " ", max_pitch
endfor

Here's a script with instructions on how to run it. It jumps back and forth between your TextGrid and Pitch object.
# open your wav file and textgrid into objects window
# select wav file
# run script
clearinfo
objName$ = selected$ ("Sound")
To Pitch: 0, 75, 600
select TextGrid 'objName$'
intervals = Get number of intervals: 1
printline 'intervals' intervals in textgrid
for i from 1 to intervals
# need var$ because it's a string
lab$ = Get label of interval: 1, i
start = Get start time of interval: 1, i
end = Get end time of interval: 1, i
# now look at the Intensity object
select Pitch 'objName$'
max = Get maximum: start, end, "Hertz", "Parabolic"
printline 'start' 'end' 'lab$' 'max'
# reset for next iteration
select TextGrid 'objName$'
endfor

Related

Using a parameter for multiple assignments

I'm simulating a network topology on multiple session lengths. I want my experiment's repetitions to increase as the session lengths decrease. So I tried tying $repeat value with *.sendBytes and failed.
Here is my attempt 1
[some config]
repeat = ${1, 10, 100} # fails
...
**.app[0].sendBytes = repeat * 1KiB
Here is my second attemp
[some config]
**.app[0].sendBytes = ${load = 1KiB, 10KiB, 100KiB}
...
repeat = 100KiB / ${load} # fails
I don't want to waste simulation time for repeating long sessions for reliability in measurements.
What you are looking for is called "Parallel Iteration" in the omnet manual:
The body of an iteration may end in an exclamation mark followed by the name of another iteration variable. This syntax denotes a parallel iteration. A parallel iteration does not define a loop of its own, but rather, the sequence is advanced in lockstep with the variable after the “!”. In other words, the “!” syntax chooses the kth value from the iteration, where k is the position (iteration count) of the iteration variable after the “!”.
An example:
**.plan = ${plan= "A", "B", "C", "D"}
**.numHosts = ${hosts= 10, 20, 50, 100 ! plan}
**.load = ${load= 0.2, 0.3, 0.3, 0.4 ! plan}
You could write something like this:
repeat = ${5, 50, 200 ! load}

Praat scripting: How to get rid of "_" in accent tier and it's corresponding syllables in Info Window?

I have a point tier that shows accents. I also have a syllable tier. I need to extract the labels of the syllable tier with the corresponding accents. The only thing that I don't need is the extracting of the label "_" and "%" in the accent tier.
My code so far:
writeInfo: ""
selectObject: "TextGrid example"
number = Get number of points: 2 #for the accent tier
for n from 1 to number
accent_time = Get time of point: 2, n
syllable = Get interval at time: 1, accent_time #for the syllable tier
syllable$ = Get label of interval: 1, syllable
accent$ = Get label of point: 2, n
#if accent$ = "_" and "%"
#don't append syllable
#endif
appendInfoLine: syllable$, " ",accent$
endfor
Result:
"Ra:n H*L
"tOm H*
gRam L*H
"tROts -
"tROts H*L
"u: H*L
"tsjo:n -
"fEst H*L
What I'm aiming to get:
"Ra:n H*L
"tOm H*
gRam L*H
"tROts H*L
"u: H*L
"fEst H*L
writeInfo: ""
selectObject: "TextGrid example"
number = Get number of points: 2 #for the accent tier
for n from 1 to number
accent_time = Get time of point: 2, n
syllable = Get interval at time: 1, accent_time #for the syllable tier
syllable$ = Get label of interval: 1, syllable
accent$ = Get label of point: 2, n
if accent$ <> "_" and accent$ <> "%"
appendInfoLine: syllable$, " ",accent$
endif
endfor

Algorithm: Overlapping 1D segments with associative key

Given an input of logical times and a unique key for each time, how do I give back a total sequence of logical times (which may be broken up) identifying each key 'present' for that time?
For example with logical times as simple integers (that can be incremented or decremented), and keys which can compared:
type LogicalTime = Int
type Key = Char
-- Not necessarily ordered
skipList :: [(LogicalTime, LogicalTime, Key)]
skipList =
[ (100, 200, 'A')
, (201, 300, 'B')
, ( 20, 400, 'C')
, (125, 150, 'D')
, (151, 250, 'E')
]
expected :: [(LogicalTime, LogicalTime, [Key])]
expected =
[ ( 20, 99, ['C'])
, (100, 124, ['A','C'])
, (125, 150, ['A','C','D'])
, (151, 200, ['A','C','E'])
, (201, 250, ['B','C','E'])
, (251, 300, ['B','C'])
, (301, 400, ['C'])
]
One may naively iterate over the entire range found and loop through every key entry to calculate this, though I'm looking for a more efficient approach.
(This is not language specific)
Each interval (start, end, key) triggers two events: add(key,start) and remove(key,end). Generate these events while iterating over the list of intervals, then sort the events by their time (start or end). Then you can go through the sorted events, generate an interval ending before the events with active keys and update the counts of keys for the next interval.
Here is some python code:
events = []
for start,end,key in skipList:
events.extend([(start-1, 1, key), (end, -1, key)])
events.sort()
startTime,_,firstKey = events.pop(0)
activeKeys = {firstKey:1}
expected = []
for time,delta,key in events:
currentKeys = [k for k in activeKeys if activeKeys[k] > 0]
currentKeys.sort()
if startTime < time:
expected.append((startTime+1, time, currentKeys))
if not key in activeKeys:
activeKeys[key] = 0
activeKeys[key] += delta
startTime = time
For your example skipList the output as expected is generated.

Sum array values up to a certain total amount

I've got an array of hashes (sorted), something like this:
testArray = [{price: 540, volume: 12},
{price: 590, volume: 18},
{price: 630, volume: 50}]
Now I want to calculate the mean value up to certain total volume. Let's say someone wants to buy 40 pieces and he wants it the cheapest way. It would mean an average price of (540*12+590*18+630*50)/40 money units.
My first attempt is following:
testArray.each do |priceHash|
#priceArray << priceHash.fetch(:price)
#volumeArray << priceHash.fetch(:volume)
end
def calculateMiddlePrice(priceArray, volumeArray, totalAmount)
result = 0
# Here some crazy wild magic happens
(0...volumeArray.count).inject(0) do |r, i|
if (volumeArray[0..i].inject(:+)) < totalAmount
r += volumeArray[i]*priceArray[i]
elsif volumeArray[0..i-1].inject(:+) < totalAmount && volumeArray[0..i].inject(:+) >= totalAmount
theRest = volumeArray[i] - (volumeArray[0..i].inject(:+) - totalAmount)
r += theRest * priceArray[i]
elsif volumeArray[0] > totalAmount
r = totalAmount * priceArray[0]
end
result = r
end
result
end
Right now I'm not even sure why it works, but it does. However this absolutely ridiculous code in my eyes.
My second thought was to cut my testArray when the total amount is achieved. The code looks better
testAmount = 31
def returnIndexForSlice(array, amount)
sum = 0
array.each_index do |index|
p sum += array[index][:volume]
if sum >= amount
return index+1
end
end
end
testArray.slice(0,returnIndexForSlice(testArray, testAmount))
Still, this just doesn't feel that right, "rubyish" if you could say so. I checked almost every method for array class, played around with bsearch, however I can't figure out a really elegant way of solving my problem.
What's crossing my mind is something like that:
amountToCheck = 31
array.some_method.with_index {|sum, index| return index if sum >= amountToCheck}
But is there such method or any other way?
Given your prices array of hashes:
prices = [ {price: 540, volume: 12},
{price: 590, volume: 18},
{price: 630, volume: 50}]
You can calculate your result in 2 steps.
def calc_price(prices, amount)
order = prices.flat_map{|item| [item[:price]] * item[:volume] } #step 1
order.first(amount).reduce(:+)/amount #step 2
end
Step 1: Create an array with each individual item in it (if the prices aren't sorted, you have to add a sort_by clause). In other words, expand the prices into a numeric array containing twelve 540's, 18 590's, etc. This uses Ruby's array repetition method: [n] * 3 = [n, n, n].
Step 2: Average the first n elements
Result:
calc_price(prices, 40)
=> 585

Algorithm to find best 8 minute window in a 1 hour run

An activity runs for a bit more than an hour. I need to get the best 8 minute window, where some parameters are maximum.
For example, a value x is measured every second. If my activity runs for one hour, I get 3600 values for x. I need to find the best continuous 8 minute time interval where the x value was the highest among all the others.
If I capture, say, from 0th minute to 8th minute, there may be another time frame like 0.4 to 8.4 where it was maximum. The granularity is one second. We need to consider every second.
Please help me with the design.
What is preventing you from just trying every possibility? 3600 values is not many. You can run through them in O(n*m) time where n in the number of data points and m in the number of points in the window.
If you want to make an optimization you can do it in O(n) by using a sliding window. Keep a queue of all the values of x within the first 8 minutes, and the total for that 8 minutes. Every time you advance one second you can dequeue the oldest value of x and subtract it from your running total. Then add the new value of x to the queue and add it to the total.
But this optimization hardly seems necessary for the size of problem you have. I'd recommend keeping it simple unless the extra performance is necessary.
Something along the lines of this:
int[] xs = { 1, 9, 5, 6, 14, 9, 6, 1, 5, 4, 7, 16, 8, 3, 2 };
int bestEndPos = 0;
int bestSum = 0;
int currentSum = 0;
for (int i = 0; i < xs.length; i++) {
// Add the current number to the sum.
currentSum += xs[i];
// Subtract the number falling out behind us.
if (i >= 8)
currentSum -= xs[i - 8];
// Record our new "best-last-index" if we beat our previous record!
if (currentSum > bestSum) {
bestEndPos = i;
bestSum = currentSum;
}
}
System.out.println("Best interval: " + (bestEndPos - 8 + 1) + "-" + bestEndPos);
System.out.println("Has interval-sum of: " + bestSum);
In Haskell!
module BestWindow where
import Data.List (tails, maximumBy, genericTake)
import Data.Ord (comparing)
import System.Random (mkStdGen, random)
type Value = Integer
type Seconds = Integer
type Window = [Seconds]
getVal :: Seconds -> Value
getVal = fst . random . mkStdGen . fromIntegral
winVal :: Window -> Value
winVal = sum . map getVal
bestWindow :: Seconds -> Seconds -> (Value, Window)
bestWindow winTime totTime = maximumBy (comparing fst) valWins
where
secs = [0 .. totTime]
wins = map (genericTake winTime) (tails secs)
vals = map winVal wins
valWins = zip vals wins
Usage:
bestWindow (8 * 60) (60 * 60) -- gives value of window and list of window seconds
there are many windows which will capture the peak value of x -- you need to define what you want a little better. the window the the maximum average value of x? of all the windows which contain the peak, the one with the highest average? lowest signal to noise ratio? the first window which contains the peak?
This is maximum subsequence problem and it can be done in O(N). google for examples.

Resources