praatrb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.autotest +25 -0
- data/.gemtest +0 -0
- data/History.txt +6 -0
- data/Manifest.txt +20 -0
- data/README.txt +74 -0
- data/Rakefile +37 -0
- data/bin/praat_lex +35 -0
- data/lib/praat.rb +88 -0
- data/lib/praat_formant.rb +19 -0
- data/lib/praat_lexer.rb +40 -0
- data/lib/praat_lexer.rex +24 -0
- data/lib/praat_lexer.rex.rb +100 -0
- data/lib/praat_parser.rb +56 -0
- data/lib/praat_pitch.rb +20 -0
- data/test/fixtures/tajm.Pitch +175 -0
- data/test/test.Pitch +6262 -0
- data/test/test_praat.rb +10 -0
- data/test/test_praat_formant.rb +8 -0
- data/test/test_praat_lexer.rb +73 -0
- data/test/test_praat_parser.rb +103 -0
- data/test/test_praat_pitch.rb +19 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bba80e61081fe0185a199334134bd12cb0efc4d5
|
4
|
+
data.tar.gz: 3546c648b01c3bdfeee01dc2cf610766e37b3723
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b83719ea8f9f5635ed2f314d0f6621cfff5b287f03ca4958e6932a1ea387dbb1eccb422862b06efe86b8e08bed56943478002d387a728bb2e49feb1491e11912
|
7
|
+
data.tar.gz: 6a29741d111d46608260172c59398c959bf5396db4e8a1412db2f09dde5e73d2f148c8e6b3ef29d9f0872141988ce2231dfbbb14a53abf1a88fc6517067737a4
|
data/.autotest
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require "autotest/restart"
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.testlib = "minitest/unit"
|
7
|
+
#
|
8
|
+
# at.extra_files << "../some/external/dependency.rb"
|
9
|
+
#
|
10
|
+
# at.libs << ":../some/external"
|
11
|
+
#
|
12
|
+
# at.add_exception "vendor"
|
13
|
+
#
|
14
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
15
|
+
# at.files_matching(/test_.*rb$/)
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# %w(TestA TestB).each do |klass|
|
19
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
# Autotest.add_hook :run_command do |at|
|
24
|
+
# system "rake build"
|
25
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/praat_lex
|
7
|
+
lib/praat.rb
|
8
|
+
lib/praat_formant.rb
|
9
|
+
lib/praat_lexer.rb
|
10
|
+
lib/praat_lexer.rex
|
11
|
+
lib/praat_lexer.rex.rb
|
12
|
+
lib/praat_parser.rb
|
13
|
+
lib/praat_pitch.rb
|
14
|
+
test/fixtures/tajm.Pitch
|
15
|
+
test/test.Pitch
|
16
|
+
test/test_praat.rb
|
17
|
+
test/test_praat_formant.rb
|
18
|
+
test/test_praat_lexer.rb
|
19
|
+
test/test_praat_parser.rb
|
20
|
+
test/test_praat_pitch.rb
|
data/README.txt
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= praat_lex
|
2
|
+
|
3
|
+
* http://www.andrewchristophersmith.com/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Provides a very malleable Praat file parser
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Pro: cool idea, doesn't need file specification
|
12
|
+
* Con: only sort of works, not really tested
|
13
|
+
|
14
|
+
The parser parses the basic grammar of Praat files, creating classes whenever
|
15
|
+
it needs them. It results in a tree of Objects and Collections, with a variety
|
16
|
+
of attributes that correspond to the grammar it finds in the file. It knows
|
17
|
+
nothing about Praat. It also only works with long text files.
|
18
|
+
|
19
|
+
== SYNOPSIS:
|
20
|
+
|
21
|
+
require 'praat'
|
22
|
+
my_collection = Praat.parse_file("my_praat_file.Collection")
|
23
|
+
# => #<Praat::Root ... >
|
24
|
+
my_collection.items[0]
|
25
|
+
# => #<Praat::Item ... >
|
26
|
+
# Let's say the first item in the collection was a Pitch object
|
27
|
+
# Collection of frames
|
28
|
+
my_collection.items[0].frames[0].candidates[0].frequency
|
29
|
+
# => 101.2358493290
|
30
|
+
|
31
|
+
== REQUIREMENTS:
|
32
|
+
|
33
|
+
* oedipux_lex
|
34
|
+
|
35
|
+
== INSTALL:
|
36
|
+
|
37
|
+
This is experimental. Only git-cloners allowed at this point.
|
38
|
+
|
39
|
+
git clone https://github.com/andrewcsmith/praatrb.git
|
40
|
+
rake install_gem
|
41
|
+
|
42
|
+
== DEVELOPERS:
|
43
|
+
|
44
|
+
After checking out the source, run:
|
45
|
+
|
46
|
+
$ rake newb
|
47
|
+
|
48
|
+
This task will install any missing dependencies, run the tests/specs,
|
49
|
+
and generate the RDoc.
|
50
|
+
|
51
|
+
== LICENSE:
|
52
|
+
|
53
|
+
(The MIT License)
|
54
|
+
|
55
|
+
Copyright (c) 2014 Andrew Christopher Smith
|
56
|
+
|
57
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
58
|
+
a copy of this software and associated documentation files (the
|
59
|
+
'Software'), to deal in the Software without restriction, including
|
60
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
61
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
62
|
+
permit persons to whom the Software is furnished to do so, subject to
|
63
|
+
the following conditions:
|
64
|
+
|
65
|
+
The above copyright notice and this permission notice shall be
|
66
|
+
included in all copies or substantial portions of the Software.
|
67
|
+
|
68
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
69
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
70
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
71
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
72
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
73
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
74
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "hoe"
|
5
|
+
require "oedipus_lex"
|
6
|
+
|
7
|
+
# Hoe.plugin :compiler
|
8
|
+
# Hoe.plugin :email
|
9
|
+
# Hoe.plugin :gem_prelude_sucks
|
10
|
+
# Hoe.plugin :history
|
11
|
+
# Hoe.plugin :inline
|
12
|
+
Hoe.plugin :minitest
|
13
|
+
# Hoe.plugin :perforce
|
14
|
+
# Hoe.plugin :racc
|
15
|
+
# Hoe.plugin :rcov
|
16
|
+
# Hoe.plugin :rdoc
|
17
|
+
# Hoe.plugin :rubygems
|
18
|
+
# Hoe.plugin :seattlerb
|
19
|
+
# Hoe.plugin :travis
|
20
|
+
|
21
|
+
Hoe.spec "praatrb" do
|
22
|
+
developer "Andrew Smith", "andrewchristophersmith@gmail.com"
|
23
|
+
dependency "oedipus_lex", "~> 2.4", :developer
|
24
|
+
|
25
|
+
self.group_name = "Andrew Smith" # if part of an organization/group
|
26
|
+
|
27
|
+
license "MIT" # this should match the license in the README
|
28
|
+
end
|
29
|
+
|
30
|
+
Rake.application.rake_require "oedipus_lex"
|
31
|
+
task :lexer => "lib/praat_lexer.rex.rb"
|
32
|
+
task :parser => :lexer
|
33
|
+
task :test => :parser
|
34
|
+
|
35
|
+
file "lib/praat_lexer.rex.rb" => "lib/praat_lexer.rex"
|
36
|
+
|
37
|
+
# vim: syntax=ruby
|
data/bin/praat_lex
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Accepts one argument: the name of the file to lex and parse. Second optional
|
3
|
+
# argument is the encoding of that file.
|
4
|
+
|
5
|
+
require 'praat'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
source_encoding = ARGV[1] || "utf-16"
|
9
|
+
|
10
|
+
begin
|
11
|
+
f = File.open(ARGV[0], "rb", {encoding: "#{source_encoding}:utf-8"})
|
12
|
+
rescue Encoding::InvalidByteSequenceError => e
|
13
|
+
# If the file reading throws an error, try with the default (utf-8) encoding.
|
14
|
+
if source_encoding != "utf-8"
|
15
|
+
source_encoding = "utf-8"
|
16
|
+
retry
|
17
|
+
else
|
18
|
+
raise e
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
s = f.read
|
23
|
+
|
24
|
+
begin
|
25
|
+
lexer = Praat::Lexer.new
|
26
|
+
parser = Praat::Parser.new
|
27
|
+
|
28
|
+
lexed = lexer.parse(s)
|
29
|
+
parsed = parser.parse(lexed)
|
30
|
+
rescue Praat::Lexer::ScanError => e
|
31
|
+
puts /(.*\n){0,3}/.match(e.message)[0]
|
32
|
+
puts e.backtrace
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
data/lib/praat.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require "praat_lexer.rb"
|
2
|
+
require "praat_parser.rb"
|
3
|
+
require "praat_pitch.rb"
|
4
|
+
require "praat_formant.rb"
|
5
|
+
|
6
|
+
module Praat
|
7
|
+
VERSION = "1.0.0"
|
8
|
+
|
9
|
+
# Parses a file given a specified encoding, returning an object containing
|
10
|
+
# nested objects
|
11
|
+
def self.parse_file filename, encoding = 'utf-8'
|
12
|
+
f = File.open(filename, "rb", {encoding: "#{encoding}:utf-8"})
|
13
|
+
Praat::Parser.new.parse(Praat::Lexer.new.parse(f.read))
|
14
|
+
end
|
15
|
+
|
16
|
+
# Turns a hz reading into a midi value.
|
17
|
+
#
|
18
|
+
# hz - The input value in hz
|
19
|
+
# base_hz - The frequency for tuning (i.e., A=440)
|
20
|
+
# base_midi - The midi key that the tuning pitch corresponds to
|
21
|
+
def self.hz_to_midi hz, base_hz = 440.0, base_midi = 69
|
22
|
+
if hz && hz > 0.0
|
23
|
+
(Math.log2(hz.to_f / base_hz) * 12.0) + base_midi
|
24
|
+
else
|
25
|
+
0.0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Something will be either a collection or an object. Only an object can have
|
30
|
+
# properties.
|
31
|
+
class MetaCollection < Array
|
32
|
+
attr_accessor :parent
|
33
|
+
|
34
|
+
def << object
|
35
|
+
object.parent = self
|
36
|
+
super object
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
self.inspect << super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class MetaObject
|
45
|
+
attr_accessor :parent
|
46
|
+
|
47
|
+
# Append the object to the collection of names
|
48
|
+
def add_to_collection name, object
|
49
|
+
instance_variable_get("@#{name}s").instance_exec(object) { |o| self << o }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add the property to the object
|
53
|
+
def add_property name, value
|
54
|
+
# Convert it to snake-case
|
55
|
+
name = sanitize_name name.to_s
|
56
|
+
|
57
|
+
# Add the attr_accessor if it doesn't exist
|
58
|
+
unless self.respond_to? "#{name}"
|
59
|
+
self.class.class_exec(name) do |n|
|
60
|
+
attr_accessor n.to_sym
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if value.respond_to? :parent=
|
65
|
+
value.parent = self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Set the attribute to the value
|
69
|
+
self.send("#{name}=", value)
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
"#{self.inspect}"
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def sanitize_name name
|
79
|
+
if name == "class"
|
80
|
+
name = "klass"
|
81
|
+
end
|
82
|
+
name.downcase.sub(' ', '_')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class Root < MetaObject; end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Praat
|
2
|
+
def self.dominant_frame item
|
3
|
+
dominant_frame = item.frames.max {|a, b|
|
4
|
+
a.intensity <=> b.intensity
|
5
|
+
}
|
6
|
+
item.add_property :dominant_frame, dominant_frame
|
7
|
+
item
|
8
|
+
end
|
9
|
+
|
10
|
+
class MetaObject; end
|
11
|
+
class Item < MetaObject
|
12
|
+
def map_formant_frequencies
|
13
|
+
self.framess.map {|frame|
|
14
|
+
frame.formants.map(&:frequency)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/lib/praat_lexer.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Praat; end
|
2
|
+
|
3
|
+
require "praat_lexer.rex.rb"
|
4
|
+
|
5
|
+
class Praat::Lexer
|
6
|
+
def do_parse
|
7
|
+
output = []
|
8
|
+
while token = next_token do
|
9
|
+
type, *vals = token
|
10
|
+
output << send("lex_#{type}", *vals)
|
11
|
+
end
|
12
|
+
output
|
13
|
+
end
|
14
|
+
|
15
|
+
def lex_float_property property, value
|
16
|
+
[:property, property.chomp, value.to_f]
|
17
|
+
end
|
18
|
+
|
19
|
+
def lex_integer_property property, value
|
20
|
+
[:property, property.chomp, value.to_i]
|
21
|
+
end
|
22
|
+
|
23
|
+
def lex_string_property property, value
|
24
|
+
[:property, property.chomp, value.chomp]
|
25
|
+
end
|
26
|
+
|
27
|
+
def lex_collection collection
|
28
|
+
[:collection, collection.chomp]
|
29
|
+
end
|
30
|
+
|
31
|
+
def lex_object object, index
|
32
|
+
[:object, object.chomp, index.to_i]
|
33
|
+
end
|
34
|
+
|
35
|
+
def lex_indent spaces
|
36
|
+
indents = spaces.length / 4
|
37
|
+
[:indent, indents]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/lib/praat_lexer.rex
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Praat; end
|
2
|
+
|
3
|
+
class Praat::Lexer
|
4
|
+
macros
|
5
|
+
INTEGER /\d+/
|
6
|
+
FLOAT /\d+\.\d+(?:e-\d\d)?/ # also captures scientific notation
|
7
|
+
NUMBER /#{FLOAT}|#{INTEGER}/
|
8
|
+
LETTER /[\w\u0250-\u02AF\u00E6\u00F0\u03B8\u014B]/ # includes IPA symbols
|
9
|
+
WORD /#{LETTER}+(?: #{LETTER}*)?/ # words may optionally have a space
|
10
|
+
rules
|
11
|
+
# Parse various tokens
|
12
|
+
/(#{WORD}) = (#{FLOAT})/ { [:float_property, *matches] }
|
13
|
+
/(#{WORD}) = (#{INTEGER})/ { [:integer_property, *matches] }
|
14
|
+
/(#{WORD}) = "(#{WORD})"/ { [:string_property, *matches] }
|
15
|
+
/(#{WORD}) \[\]:/ { [:collection, *matches] }
|
16
|
+
/(#{WORD}) \[(#{INTEGER})\]:/ { [:object, *matches] }
|
17
|
+
/( {4}+)/ { [:indent, *matches] }
|
18
|
+
|
19
|
+
# Trailing whitespace and empty lines
|
20
|
+
/\s*\n/
|
21
|
+
end
|
22
|
+
|
23
|
+
# vim: filetype=ruby
|
24
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#--
|
3
|
+
# This file is automatically generated. Do not modify it.
|
4
|
+
# Generated by: oedipus_lex version 2.4.0.
|
5
|
+
# Source: lib/praat_lexer.rex
|
6
|
+
#++
|
7
|
+
|
8
|
+
module Praat; end
|
9
|
+
|
10
|
+
class Praat::Lexer
|
11
|
+
require 'strscan'
|
12
|
+
|
13
|
+
INTEGER = /\d+/
|
14
|
+
FLOAT = /\d+\.\d+(?:e-\d\d)?/
|
15
|
+
NUMBER = /#{FLOAT}|#{INTEGER}/
|
16
|
+
LETTER = /[\w\u0250-\u02AF\u00E6\u00F0\u03B8\u014B]/
|
17
|
+
WORD = /#{LETTER}+(?: #{LETTER}*)?/
|
18
|
+
|
19
|
+
class ScanError < StandardError ; end
|
20
|
+
|
21
|
+
attr_accessor :filename
|
22
|
+
attr_accessor :ss
|
23
|
+
attr_accessor :state
|
24
|
+
|
25
|
+
alias :match :ss
|
26
|
+
|
27
|
+
def matches
|
28
|
+
m = (1..9).map { |i| ss[i] }
|
29
|
+
m.pop until m[-1] or m.empty?
|
30
|
+
m
|
31
|
+
end
|
32
|
+
|
33
|
+
def action
|
34
|
+
yield
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def scanner_class
|
39
|
+
StringScanner
|
40
|
+
end unless instance_methods(false).map(&:to_s).include?("scanner_class")
|
41
|
+
|
42
|
+
def parse str
|
43
|
+
self.ss = scanner_class.new str
|
44
|
+
self.state ||= nil
|
45
|
+
|
46
|
+
do_parse
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_file path
|
50
|
+
self.filename = path
|
51
|
+
open path do |f|
|
52
|
+
parse f.read
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def next_token
|
57
|
+
|
58
|
+
token = nil
|
59
|
+
|
60
|
+
until ss.eos? or token do
|
61
|
+
token =
|
62
|
+
case state
|
63
|
+
when nil then
|
64
|
+
case
|
65
|
+
when text = ss.scan(/(#{WORD}) = (#{FLOAT})/) then
|
66
|
+
action { [:float_property, *matches] }
|
67
|
+
when text = ss.scan(/(#{WORD}) = (#{INTEGER})/) then
|
68
|
+
action { [:integer_property, *matches] }
|
69
|
+
when text = ss.scan(/(#{WORD}) = "(#{WORD})"/) then
|
70
|
+
action { [:string_property, *matches] }
|
71
|
+
when text = ss.scan(/(#{WORD}) \[\]:/) then
|
72
|
+
action { [:collection, *matches] }
|
73
|
+
when text = ss.scan(/(#{WORD}) \[(#{INTEGER})\]:/) then
|
74
|
+
action { [:object, *matches] }
|
75
|
+
when text = ss.scan(/( {4}+)/) then
|
76
|
+
action { [:indent, *matches] }
|
77
|
+
when text = ss.scan(/\s*\n/) then
|
78
|
+
# do nothing
|
79
|
+
else
|
80
|
+
text = ss.string[ss.pos .. -1]
|
81
|
+
raise ScanError, "can not match (#{state.inspect}): '#{text}'"
|
82
|
+
end
|
83
|
+
else
|
84
|
+
raise ScanError, "undefined state: '#{state}'"
|
85
|
+
end # token = case state
|
86
|
+
|
87
|
+
next unless token # allow functions to trigger redo w/ nil
|
88
|
+
end # while
|
89
|
+
|
90
|
+
raise "bad lexical result: #{token.inspect}" unless
|
91
|
+
token.nil? || (Array === token && token.size >= 2)
|
92
|
+
|
93
|
+
# auto-switch state
|
94
|
+
self.state = token.last if token && token.first == :state
|
95
|
+
|
96
|
+
token
|
97
|
+
end # def next_token
|
98
|
+
end # class
|
99
|
+
|
100
|
+
# vim: filetype=ruby
|
data/lib/praat_parser.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Praat; end
|
2
|
+
|
3
|
+
class Praat::Parser
|
4
|
+
def parse input
|
5
|
+
output = Praat::Root.new
|
6
|
+
@current_node = output
|
7
|
+
@current_indent = 0
|
8
|
+
input.each do |item|
|
9
|
+
case item.shift
|
10
|
+
when :indent
|
11
|
+
process_indent item
|
12
|
+
when :collection
|
13
|
+
@current_node.add_property "#{item.first}s", create_collection(item.first)
|
14
|
+
@current_node = @current_node.send("#{item.first}s")
|
15
|
+
when :object
|
16
|
+
@current_node << create_object(item.first)
|
17
|
+
@current_node.last.parent = @current_node
|
18
|
+
@current_node = @current_node.last
|
19
|
+
when :property
|
20
|
+
@current_node.add_property(*item)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
output
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def process_indent item
|
29
|
+
indent = item.first
|
30
|
+
# If the new indent is a backstep
|
31
|
+
if indent < @current_indent
|
32
|
+
# Go back
|
33
|
+
(@current_indent - indent).times do
|
34
|
+
@current_node = @current_node.parent
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@current_indent = item.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_collection klass
|
41
|
+
klass = klass.capitalize << "s"
|
42
|
+
unless Object.const_defined? "Praat::#{klass}"
|
43
|
+
Praat.class_eval "class #{klass} < Praat::MetaCollection; end"
|
44
|
+
end
|
45
|
+
(Praat.const_get "#{klass}").new
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_object klass
|
49
|
+
klass = klass.capitalize
|
50
|
+
unless Object.const_defined? "Praat::#{klass}"
|
51
|
+
Praat.class_eval "class #{klass} < Praat::MetaObject; end"
|
52
|
+
end
|
53
|
+
(Praat.const_get "#{klass}").new
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/praat_pitch.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Praat
|
2
|
+
def self.find_dominant_pitch item
|
3
|
+
item.frames.map! do |frame|
|
4
|
+
top = frame.candidates.max do |a, b|
|
5
|
+
a.strength <=> b.strength
|
6
|
+
end
|
7
|
+
|
8
|
+
frame.add_property "freq", top.frequency
|
9
|
+
|
10
|
+
# Filter out the unvoiced candidates
|
11
|
+
if frame.freq > item.ceiling
|
12
|
+
frame.freq = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
frame
|
16
|
+
end
|
17
|
+
item
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|