praat - delete segment - audio

I have several speech files and I need to cut a certain part of the sound file, from 0.21 milliseconds to 0.45 milliseconds. The script below will select the sound segment from 0.21 milliseconds to 0.45 milliseconds and save it. I want to cut the segment from the speech file and then save it without it. I should probably add another line after "Move end of selection to nearest zero crossing" and change the "Write selected sound..." but I am not sure how exactly.
form Files
sentence InputDir ./
endform
createDirectory ("output")
Create Strings as file list... list 'inputDir$'*.wav
numberOfFiles = Get number of strings
for ifile to numberOfFiles
select Strings list
fileName$ = Get string... ifile
Read from file... 'inputDir$''fileName$'
sound_name$ = selected$ ("Sound")
select Sound 'sound_name$'
Edit
editor Sound 'sound_name$'
Select... 0.21 0.45
Move start of selection to nearest zero crossing
Move end of selection to nearest zero crossing
Write selected sound to WAV file... ./output/'fileName$'
endeditor
select all
minus Strings list
Remove
endfor
select all
Remove

I want to cut the segment from the speech file and then save it without it
It's not clear what you want to do with the deleted segment. Do you want to edit it out (as in, shorten the total duration of the sound?) or simply silence it (as in set the samples contained within to zero?).
Either way, you don't need to open the sound editor (the window with the sound wave and the spectrogram). Below I reproduced your script with some alternatives (and updated the syntax).
form Files
sentence Input_dir ./
positive Start 0.21
positive End 0.45
endform
createDirectory("output")
list = Create Strings as file list: "list", input_dir$ + "*.wav"
numberOfFiles = Get number of strings
for ifile to numberOfFiles
selectObject: list
fileName$ = Get string: ifile
sound = Read from file: input_dir$ + fileName$
sound_name$ = selected$("Sound")
# Find zero crossings
start = Get nearest zero crossing: 1, start
end = Get nearest zero crossing: 1, end
sound_end = Get total duration
# Cut the selected part out, shortening the sound
# by extracting the part before and after and concatenating
before = Extract part: 0, start, "rectangular", 1, "no"
selectObject: sound
after = Extract part: end, sound_end, "rectangular", 1, "no"
selectObject: before, after
new = Concatenate
removeObject: before, after
## Or, if you want to set the selected part to zero
## (since we already have the zero crossings)
# new = Set part to zero: start, end, "at exactly these times"
## Or, if what you want is to get only the selected part
## and not the original sound
# new = Extract part: start, end, "rectangular", 1, "no"
# Either way, the new, modified sound is selected
# and its ID is stored in `new`
Save as WAV file: "./output/" + fileName$
# I prefer a less shotgunny way to remove unwanted objects
removeObject: sound, new
endfor
removeObject: list

Related

How do I listen to a specific text string on Mac OS X in a livecode application

I want to create a Mac app similar to Textexpander or Atext. Both these applications allow the user to define snippets along with their respective trigger words. Typing the trigger words in any app, replaces that trigger word with the actual snippet defined.
I presume that the app listens to all strings being typed in any app and when it detects a string matching one of the trigger words defined, it replaces it with the snippet.
Is that how it actually works, or is there some other way?
Make two fields. In field 2 put something like:
time xyz
come ABC
In the script of field 1:
on textChanged
if the last char of me = space then
put the last word of me into temp
if temp is in fld 2 then
repeat for each word tWord in fld 2
put the last word of line lineOffset(temp,fld 2) of fld 2 into the last word of me
exit repeat
end repeat
end if
select after text of me
end if
end textChanged
Now type into fld 1, you know, "Now is the time for all good men to come to the aid of their country". This can be better done with an array, but the concept may be more accessible here.
This is a better handler, since it will not react to the trigger word:
on textChanged
if the last char of me = space then
put the last word of me into stringOfInterest
put fld 2 into dataToSearch
if stringOfInterest is in dataToSearch then
repeat for each line tLine in dataToSearch
if word 1 of tLine = stringOfInterest then
put word 2 of tLine into the last word of me
exit repeat
end if
end repeat
end if
select after text of me
end if
end textChanged

Splitting a string of a multiline textbox by lines

I want to split the text of a textbox after a specific amount of visible lines.
I've found some codes that "allows that", but all of them consider the lines by the "vbCrLf" parameter, but i want to split using the visible lines of a multiline textbox.
To make it more clear to understand, consider a multiline textbox with the following text:
"The history of textbooks dates back to civilizations of ancient history. For example, Ancient Greeks wrote texts intended for education. The modern textbook has its roots in the standardization made possible by the printing press. Johannes Gutenberg himself may have printed editions of Ars Minor, a schoolbook on Latin grammar by Aelius Donatus. Early textbooks were used by tutors and teachers, who used the books as instructional aids (e.g., alphabet books), as well as individuals who taught themselves."
When i use the Textbox.Linecount function it returns the number 6 because the textbox shows six lines (which depends on the size of the control), but if i use a function like strText = Split(TextBox.Text, vbCrLf) it will return 1, because there is only one vbCrLf. But i need to split the text into two textbox considering the visible lines of the control, something like what happens in page breaks of MS Word.
For a better visual explanation, please look at the attached image.
Example
Firstly, I'm not convinced there is a robust and elegant way to do this, but it was fun to experiment and it might be useful to you.
The following will split the contents of TextBoxInput into TextBoxPage1 and TextBoxPage2 breaking on the line number specified by PAGED_TEXT_BOX_LINES.
It uses the textbox itself to detect natural line breaks and thus implicitly caters for the size of the textbox, the font, etc.
The desired line count is hard coded as a constant - not doing this would require an alternative of calculating the line height of the textbox (requiring calculations based on the font metrics and the textbox's internal line-leading size).
It only handles two "pages". But the concept could be extended simply by repeating the process based on the remainder of text that ends up in TextBoxPage2.
Private Sub CommandButton1_Click()
Const PAGED_TEXT_BOX_LINES As Integer = 5
Dim text As String
Dim i As Long
Dim textLength As Long
Dim curLine As Integer
text = TextBoxInput.text
textLength = Len(text)
TextBoxPage1.SetFocus
'add characters of the input string until the first page textbox
' exceeds maximum line count
For i = 1 To textLength
TextBoxPage1.text = Mid$(text, 1, i)
If TextBoxPage1.LineCount > PAGED_TEXT_BOX_LINES Then
'retreat cursor until we reach previous line, so we can
' detect the word that wrapped
curLine = TextBoxPage1.curLine
Do While TextBoxPage1.curLine = curLine
TextBoxPage1.SelStart = TextBoxPage1.SelStart - 1
Loop
'the remaining text after the SelStart is what
' wrapped, so stop page 1 after SelStart
TextBoxPage1.text = Mid$(text, 1, TextBoxPage1.SelStart)
TextBoxPage2.text = Trim$(Mid$(text, TextBoxPage1.SelStart + 1))
Exit For
End If
Next i
End Sub

How to save manipulated WAV files in object list?

I have the following problem: I want to low-pass filter 240 WAV files. The script is running only till the low-pass filtered sounds are created and shown in the object list ("..._band"). However, Praat does not export them as WAV files. After choosing the output folder, I get the warning message "Command 'Get number of strings' not available for current selection".
In short, my question is how can I save the WAV sounds in the object list individually with their new file names? See also Screenshot.
Script see below.
Thank you very much for your help!
Greetings,
#determine praat version
ver1$ = left$(praatVersion$, (rindex(praatVersion$, ".")-1));
ver1 = 'ver1$'
if ver1 < 5.2
exit Please download a more recent version of Praat
endif
if ver1 == 5.2
ver2$ = right$(praatVersion$, length(praatVersion$) - (rindex(praatVersion$, ".")));
ver2 = 'ver2$'
if ver2 < 4
exit Please download a more recent version of Praat (minor)
endif
endif
beginPause ("Low-Pass Filter Instructions")
comment ("1. Select a folder containing the wave files to be low-pass filtered")
comment ("2. Wave files will be low-pass filtered (0 - 400 Hz)")
comment ("3. Select an output folder for the low-pass filtered wave files to be saved to")
comment ("Click 'Next' to begin")
clicked = endPause("Next", 1);
#wavefile folder path
sourceDir$ = chooseDirectory$ ("Select folder containing wave files")
if sourceDir$ == ""
exit Script exited. You did not select a folder.
else
sourceDir$ = sourceDir$ + "/";
endif
Create Strings as file list... list 'sourceDir$'/*.wav
numberOfFiles = Get number of strings
levels$ = ""
for ifile to numberOfFiles
select Strings list
currentList = selected ("Strings")
filename$ = Get string... ifile
Read from file... 'sourceDir$'/'filename$'
currentSound = selected ("Sound")
filterFreqRange = Filter (pass Hann band)... 0 400 20
select currentSound
Remove
endfor
select currentList
Remove
#output folder path - where the wave files get saved
outputDir$ = chooseDirectory$ ("Select folder to save wave files")
if outputDir$ == ""
exit Script exited. You did not select a folder.
else
outputDir$ = outputDir$ + "/";
endif
numberOfFiles = Get number of strings
for ifile to numberOfFiles
select Strings list
currentList = selected ("Strings")
filename$ = Get string... ifile
currentSound = selected ("Sound")
endif
Save as WAV file... 'outputDir$'/'filename$'
select currentSound
Remove
endfor
#clean up
select currentList
Remove
#clear the info window
clearinfo
#print success message
printline Successfully low-pass filtered 'numberOfFiles' wave files.
At a glance, the command is not available because when you get to that point in the script the selection is empty. It is empty because at the end of the first loop, you select your Strings object and then Remove it.
More generally, your script is not handling the object selection properly, which is a big problem in Praat because available commands change depending on the active selection.
So even if you remove the line where you Remove the list, you will bump into a problem the second time you run Get number of strings because by then you have changed the selection. And even if you remove that line (which you don't really need), you'll still bump into a problem when you run selected("Sound") after selecting the Strings object, because by then you won't have any selected Sound objects (you didn't have them before anyway).
A more idiomatic version of your script, which also runs on a single loop where sounds are read, filtered, and removed one by one (which is also more memory efficient) would look like this:
form Low-Pass Filter...
real From_frequency_(Hz) 0
real To_frequency_(Hz) 400
real Smoothing_(Hz) 20
comment Leave paths empty for GUI selectors
sentence Source_dir
sentence Output_dir
endform
if praatVersion < 5204
exitScript: "Please download a more recent version of Praat"
endif
if source_dir$ == ""
source_dir$ = chooseDirectory$("Select folder containing wave files")
if source_dir$ == ""
exit
endif
endif
if output_dir$ == ""
output_dir$ = chooseDirectory$("Select folder to save filtered files")
if output_dir$ == ""
exit
endif
endif
list = Create Strings as file list: "list", source_dir$ + "/*.wav"
numberOfFiles = Get number of strings
levels$ = ""
for i to numberOfFiles
selectObject: list
filename$ = Get string: i
sound = Read from file: source_dir$ + "/" + filename$
filtered = Filter (pass Hann band): from_frequency, to_frequency, smoothing
Save as WAV file: output_dir$ + "/" + selected$("Sound")
removeObject: sound, filtered
endfor
Although you might be interested to know that, if you do not need the automatic file reading and saving (ie, if you are OK with having your script work on objects from the list) your script could be reduced to
Filter (pass Hann band): 0, 400, 20
which works on multiple selected Sound objects.
If you absolutely need the looping (ie, if you'll be working on really large sets of files) you might also be interested in using the vieweach plugin, with was written to try and minimise this sort of boilerplate (full disclaimer: I wrote the plugin). I wrote a longer blog post about it as well.

parsing specific data from .txt file to excel or something else

I have extracted data from one source to .txt file. Source is some sort of address book and I used macro recorder for extraction. Now I have several files which are formated exactly in next way (example on 4 contacts):
Abbrucharbeiten
ATR Armbruster
Werkstr. 28
78727 Oberndorf
Tel. 0175 7441784
Fax 07423 6280
Abbrucharbeiten
Jensen & Sohn, Karl
Schallenberg 6A
25587 Münsterdorf
Tel. 04821 82538
Fax 04821 83381
Abbrucharbeiten
Kiwitt, R.
Auf der Heide 54
48282 Emsdetten
Tel. 02572 88559
Tel. 0172 7624359
Abbrucharbeiten, Sand und Kies, Transporte, Kiesgruben, Erdbau
Josef Grabmeier GmbH
Reitgesing 1
85560 Ebersberg
Tel. 08092 24701-0
Fax 08092 24701-24
1st row is always field(name) of bussines
2nd row is always name of company/firm
3rd row is always street adress
4th row is always Zip code and Place
and then
5th row and next couple of rows (sometimes are two rows sometimes more) are eithar Tel. or Fax.
I want to format it so it would be something like excel sheet like:
Branche: Name: Address: Place: contact1: contact2:
1st row 2nd row 3rd row 4th row 5th row 6th row.....
Now the main problem is I have over 500.000 contacts and my main problems are last fields which aren't always the same number... I don't wan't to do it manually, please help me...
Neither python nor visual basic but shouldn't be very difficult to translate to those languages. This is perl.
perl -lne '
## Print header. Either the header and data will be separated with pipes.
## Contacts(contact1, contact2, etc) are not included because at this
## moment I can not know how many there will be. It could be done but script
## would be far more complex.
BEGIN {
push #header, q|Branche:|, q|Name:|, q|Address:|, q|Place:|;
printf qq|%s\n|, join q{|}, #header;
}
## Save information for each contact. At least six lines. Over that only
## if lines begins with strings "Tel" or "Fax".
if ( $line < 6 || m/\A(?i)tel|fax/ ) {
push #contact_info, $_;
++$line;
## Not skip the printing of last contact.
next unless eof;
}
## Print info of contact, initialize data structures and repeat process
## for the next one.
printf qq|%s\n|, join q{|}, #contact_info;
$line = 0;
undef #contact_info;
push #contact_info, $_;
++$line;
' infile
It's a one-liner (I know it doesn't seem, but you can get rid of comments and remove newlines to get it), so run it directly from your shell. It yields:
Branche:|Name:|Address:|Place:
Abbrucharbeiten|ATR Armbruster|Werkstr. 28|78727 Oberndorf |Tel. 0175 7441784|Fax 07423 6280
Abbrucharbeiten|Jensen & Sohn, Karl|Schallenberg 6A|25587 Münsterdorf|Tel. 04821 82538|Fax 04821 83381
Abbrucharbeiten|Kiwitt, R.|Auf der Heide 54|48282 Emsdetten|Tel. 02572 88559|Tel. 0172 7624359
Abbrucharbeiten, Sand und Kies, Transporte, Kiesgruben, Erdbau|Josef Grabmeier GmbH|Reitgesing 1|85560 Ebersberg|Tel. 08092 24701-0|Fax 08092 24701-24
Take into account that I didn't print the full header and that fields are separated with pipes. I think that is not problematic to import it in Excel.

Read CSV file as Array with AppleScript

I would like to read in a CSV file in as a 2D array and then return it back to a CSV file.
Let's say that this is my CSV file. It is an excel file and the | implies the adjacent cell:
family | type
Doctor | Pediatrics
Engineer | Chemical
From what I understand, there are no arrays on applescript, just lists and records. If it would be better to do this with a XLSX file, please let me know.
Nigel's CSV-to-list converter is the best I have seen ...
http://macscripter.net/viewtopic.php?pid=125444#p125444
For your example, use these settings:
set csvText to "family | type
Doctor | Pediatrics
Engineer | Chemical"
csvToList(csvText, {separator:"|"}, {trimming:true})
v2
set csvText to read "/Users/user1385816/Desktop/yourfile.csv"
csvToList(csvText, {}, {trimming:true})
An array is just a list in applescript, so you want a 2d array or a list-of-lists in applescript-speak. If you understand applescript's text item delimiters then your task is just simple manipulation to convert strings into lists and vice versa. So I wrote you a couple handlers to make the task easy for you; textToTwoDArray() and twoDArrayToText(). This first example shows how to convert your string into a list-of-lists using textToTwoDArray().
NOTE: you have to be careful of the line endings in a text file because they can be either a carriage return (character id 13) or a line feed (character id 10). You can see I used character id 10 in my code but if you aren't getting the proper results try "13".
set fileText to "family | type
Doctor | Pediatrics
Engineer | Chemical"
textToTwoDArray(fileText, character id 10, " | ")
on textToTwoDArray(theText, mainDelimiter, secondaryDelimiter)
set {tids, text item delimiters} to {text item delimiters, mainDelimiter}
set firstArray to text items of theText
set text item delimiters to secondaryDelimiter
set twoDArray to {}
repeat with anItem in firstArray
set end of twoDArray to text items of anItem
end repeat
set text item delimiters to tids
return twoDArray
end textToTwoDArray
And here's how to convert a list-of-lists back into your string using twoDArrayToText().
set twoDArray to {{"family", "type"}, {"Doctor", "Pediatrics"}, {"Engineer", "Chemical"}}
twoDArrayToText(twoDArray, character id 10, " | ")
on twoDArrayToText(theArray, mainDelimiter, secondaryDelimiter)
set {tids, text item delimiters} to {text item delimiters, secondaryDelimiter}
set t to ""
repeat with anItem in theArray
set t to t & (anItem as text) & mainDelimiter
end repeat
set text item delimiters to tids
return (text 1 thru -2 of t)
end twoDArrayToText
So now all you have to do is figure out how to read and write to a text file with applescript. Good luck ;)
If your question is just about modeling your CSV data in AppleScript, the solution is to use a list of records like this:
set csvData to {{family:"Doctor", type:"Engineer"}, {family:"Engineer", type:"Chemical"}}
you can then read that out again inside a repeat with aRow in csvData loop.
A technical note: AppleScript lists are implemented as vectors, meaning they are ordered and can be accessed by numerical index (beginning at index 1) – they behave much like an array in most other languages.

Resources