forked from hataori-p/real-voice
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotesToTextGrid.lua
138 lines (118 loc) · 3.93 KB
/
notesToTextGrid.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
SCRIPT_TITLE = "RV Notes to TextGrid"
-- Ver.1 - exports notes and lyrics to Praat's textGrid object, pitch encoded in lyrics,
-- after editing in Praat it can be loaded back by "RV Notes from TextGrid" ver.2
function getClientInfo()
return {
name = SV:T(SCRIPT_TITLE),
author = "Hataori@protonmail.com",
category = "Real Voice",
versionNumber = 1,
minEditorVersion = 65537
}
end
local inputForm = {
title = SV:T("Notes to Praat Textgrid"),
message = SV:T("Exports notes to a textgrid file"),
buttons = "OkCancel",
widgets = {
{
name = "file", type = "TextBox",
label = SV:T("filePath/fileName.txt"),
default = "[projectDir]/[projectName]_textGrid.txt"
}
}
}
local function getProjectPathName()
local projectFileName = SV:getProject():getFileName()
if not projectFileName then return end
local projectName, projectDir
projectFileName = projectFileName:gsub("\\", "/")
projectDir, projectName = projectFileName:match("^(.*/)([^/]+)%.svp$")
if not projectDir or not projectName then error(SV:T("project dir or name not found")) end
return projectName, projectDir
end
local function process()
local dlgResult = SV:showCustomDialog(inputForm)
if not dlgResult.status then return end -- cancel pressed
-- output file
local filePathName = dlgResult.answers.file or ""
if filePathName == "" then filePathName = "[projectDir]/[projectName]_textGrid.txt" end
if filePathName:match("%[projectDir%]") or filePathName:match("%[projectName%]") then
local projectName, projectDir = getProjectPathName()
filePathName = filePathName:gsub("%[projectDir%]", projectDir)
filePathName = filePathName:gsub("%[projectName%]", projectName)
end
filePathName = filePathName:gsub("\\", "/")
filePathName = filePathName:gsub("/+", "/")
-- synthv structures
local project = SV:getProject()
local timeAxis = project:getTimeAxis()
local scope = SV:getMainEditor():getCurrentGroup()
local group = scope:getTarget()
local notes, maxtime = {}, 0
for i = 1, group:getNumNotes() do
local note = group:getNote(i)
local lyr = note:getLyrics()
local pitch = note:getPitch() - 69 -- midi offset
local blOnset, blEnd = note:getOnset(), note:getEnd()
local tons = timeAxis:getSecondsFromBlick(blOnset) -- start time
local tend = timeAxis:getSecondsFromBlick(blEnd) -- end time
table.insert(notes, {
lyr = lyr,
pitch = pitch,
tstart = tons,
tend = tend
})
if tend > maxtime then maxtime = tend end
end
maxtime = maxtime + 1.0
-- number of intervals
local cnt = 0
local pretim = 0
for _, nt in ipairs(notes) do
if math.abs(nt.tstart - pretim) > 0.0001 then
cnt = cnt + 1
end
cnt = cnt + 1
pretim = nt.tend
end
cnt = cnt + 1
-- write to file
local fo = io.open(filePathName, "w")
fo:write("File type = \"ooTextFile\"\n")
fo:write("Object class = \"TextGrid\"\n")
fo:write("\n")
fo:write("0\n")
fo:write(maxtime.."\n")
fo:write("<exists>\n")
fo:write("1\n")
fo:write("\"IntervalTier\"\n")
fo:write("\"Notes\"\n")
fo:write("0\n")
fo:write(maxtime.."\n")
fo:write(cnt.."\n")
local pretim = 0
for _, nt in ipairs(notes) do
if math.abs(nt.tstart - pretim) > 0.0001 then
fo:write(pretim.."\n")
fo:write(nt.tstart.."\n")
fo:write("\"\"\n")
fo:write(nt.tstart.."\n")
fo:write(nt.tend.."\n")
fo:write("\""..nt.lyr.." ("..nt.pitch..")\"\n")
else
fo:write((nt.tstart).."\n")
fo:write(nt.tend.."\n")
fo:write("\""..nt.lyr.." ("..nt.pitch..")\"\n")
end
pretim = nt.tend
end
fo:write(pretim.."\n")
fo:write((pretim + 1.0).."\n")
fo:write("\"\"\n")
fo:close()
end
function main()
process()
SV:finish()
end