ref: c73268a2551636b16dbae7652697361fed4e6e9f
dir: /plugins/wavesurfer/aubio.plug/
# -*-Mode:Tcl-*-
#
# Copyright (C) 2000-2004 Jonas Beskow and Kare Sjolander
#
# This file is part of the WaveSurfer package.
# The latest version can be found at http://www.speech.kth.se/wavesurfer/
#
# -----------------------------------------------------------------------------
wsurf::RegisterPlugin transcription \
-description "This plug-in is used to create transcription panes. Use the\
properties-dialog to specify which transcription file that should be\
displayed in a pane. It is usually practical to create a special\
configuration for a certain combination of sound and transcription\
files, specifying file properties such as filename extension, format,\
file path, and encoding. There are\
many options to control appearance and\
editing functionality. Depending on the transcription file format\
additional options might be available. There is a special pop-up menu\
with functions to edit, play, convert and search labels. Unicode\
characters are supported if using the source version of WaveSurfer,\
in order to keep the binary versions small. The transcription plug-in is\
used in combination with format handler plug-ins which handle\
the conversion between file formats and the internal format\
used by the transcription plug-in." \
-url "http://www.speech.kth.se/wavesurfer/" \
-addmenuentriesproc trans::addMenuEntries \
-widgetcreatedproc trans::widgetCreated \
-widgetdeletedproc trans::widgetDeleted \
-panecreatedproc trans::paneCreated \
-panedeletedproc trans::paneDeleted \
-redrawproc trans::redraw \
-getboundsproc trans::getBounds \
-cursormovedproc trans::cursorMoved \
-printproc trans::print \
-propertiespageproc trans::propertyPane \
-applypropertiesproc trans::applyProperties \
-getconfigurationproc trans::getConfiguration \
-openfileproc trans::openFile \
-savefileproc trans::saveFile \
-needsaveproc trans::needSave \
-cutproc trans::cut \
-copyproc trans::copy \
-pasteproc trans::paste \
-stateproc trans::state \
-playproc trans::play \
-stopproc trans::stop \
-registercallbackproc trans::regCallback \
-soundchangedproc trans::soundChanged
# -----------------------------------------------------------------------------
namespace eval trans {
variable Info
set Info(path) ""
}
# -----------------------------------------------------------------------------
proc trans::addMenuEntries {w pane m hook x y} {
if {[string match query $hook]} {
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
return 1
}
}
return 0
}
if {[string match main $hook]} {
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
for {set j 0} {$j < $v(menuNcols)} {incr j } {
for {set i 0} {$i < $v(menuNrows)} {incr i } {
if {$i==0} {set cb 1} else {set cb 0}
$m add command -label [subst $v($i$j)] -columnbreak $cb \
-command [namespace code [list InsertLabel $w $pane $x $y \
[subst $v($i$j)]]] \
-font $v(font)
}
}
$m add command -label "Onsets Detection ..." \
-command [namespace code [list getComputeAubioOnset $w $pane]]
$m add command -label "Play Label" -columnbreak 1 \
-command [namespace code [list PlayLabel $w $pane $x $y]]
$m add command -label "Insert Label" \
-command [namespace code [list InsertLabel $w $pane $x $y]]
$m add command -label "Select Label" \
-command [namespace code [list SelectLabel $w $pane $x $y]]
$m add command -label "Align Label" \
-command [namespace code [list AlignLabel $w $pane $x $y]]
$m add command -label "Browse..." \
-command [namespace code [list browse $w $pane]]
$m add command -label "Delete Label" \
-command [namespace code [list DeleteLabel $w $pane $x $y]]
#$m add separator
$m add command -label "Convert..." \
-command [namespace code [list convert $w $pane]]
$m add command -label "Load Transcription..." \
-command [namespace code [list getOpenTranscriptionFile $w $pane]]
$m add command -label "Load Text Labels..." \
-command [namespace code [list getOpenTextLabelFile $w $pane]]
$m add command -label "Save Transcriptions" \
-command [namespace code [list saveTranscriptionFiles $w $pane]]
$m add command -label "Save Transcription As..." \
-command [namespace code [list getSaveTranscriptionFile $w $pane]]
$m add command -label "Split Sound on Labels" \
-command [namespace code [list SplitSoundFile $w $pane]]
}
}
}
if {[string match create $hook]} {
$m.$hook add command -label "AubioTranscription" \
-command [namespace code [list createTranscription $w $pane]]
} elseif {[string length $hook] == 0} {
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
}
}
}
}
proc trans::widgetCreated {w} {
variable Info
set Info($w,active) ""
}
proc trans::widgetDeleted {w} {
variable Info
foreach key [array names Info $w*] {unset Info($key)}
}
proc trans::paneCreated {w pane} {
namespace eval [namespace current]::${pane} {
variable var
}
upvar [namespace current]::${pane}::var v
set v(drawTranscription) 0
# foreach otherpane [$w _getPanes] {
# upvar wsurf::trans::${otherpane}::var ov
# if {[info exists ov(extBounds)] && $ov(extBounds)} {
# puts aaa
# $w _redraw
# }
# }
}
proc trans::paneDeleted {w pane} {
upvar [namespace current]::${pane}::var v
foreach otherpane [$w _getPanes] {
if {$pane == $otherpane} continue
upvar wsurf::analysis::${otherpane}::var ov
upvar wsurf::dataplot::${otherpane}::var dv
if {$ov(drawWaveform) || $ov(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
if {[winfo exists $othercanvas]} {
$othercanvas delete tran$pane
}
}
}
namespace delete [namespace current]::${pane}
}
proc trans::createTranscription {w pane} {
set pane [$w addPane -before $pane -height 20 -closeenough 3 \
-minheight 20 -maxheight 20]
addTranscription $w $pane
}
### Add-ons from Paul Brossier <piem@altern.org>
proc trans::getComputeAubioOnset {w pane} {
set execFileName aubioonset
#exec which $execFileName > /dev/null || echo "$execFileName not found in the path"
# save selection to a file
# (from wavesurfer.tcl : SaveSelection)
set w [::wsurf::GetCurrent]
BreakIfInvalid $w
# select all
set pane [lindex [$w _getPanes] 0]
if {$pane != ""} {
set length [$pane cget -maxtime]
} else {
set length [[$w cget -sound] length -unit seconds]
}
$w configure -selection [list 0.0 $length]
# run on selection
foreach {left right} [$w cget -selection] break
if {$left == $right} return
set s [$w cget -sound]
set start [expr {int($left*[$s cget -rate])}]
set end [expr {int($right*[$s cget -rate])}]
set path [file dirname [$w getInfo fileName]]
set tmpdir $::wsurf::Info(Prefs,tmpDir)
set fileName "$tmpdir/wavesurfer-tmp-aubio.snd"
set fileNameTxt "$tmpdir/wavesurfer-tmp-aubio.txt"
set aubioThreshold 0.2
#[snack::getSaveFile -initialdir $path \
#-format $::surf(fileFormat)]
#if {$fileName == ""} return
$s write $fileName -start $start -end $end -progress progressCallback
# system command : compute onsets
exec aubioonset -i $fileName -t $aubioThreshold > $fileNameTxt 2> /dev/null
# some ed hacks to put the .txt in .lab format
# copy the times 3 times: 0.0000 0.0000 0.0000
exec echo -e "e $fileNameTxt\\n,s/\\(.*\\)/\\\\1 \\\\1 \\\\1/\\nwq" | ed 2> /dev/null
# open the file as a labelfile
openTranscriptionFile $w $pane $fileNameTxt labelfile
# delete both files
exec rm -f $fileName $fileNameTxt
$w _redrawPane $pane
}
proc trans::getOpenTranscriptionFile {w pane} {
variable Info
upvar [namespace current]::${pane}::var v
if {$v(changed)} {
if {[string match no [tk_messageBox -message "You have unsaved changes.\nDo you really want to continue?" -type yesno -icon question]]} {
return
}
}
set file [file tail $v(fileName)]
if {$Info(path) != ""} {
set path $Info(path)
} else {
if {$v(labdir) == ""} {
set path [file dirname $v(fileName)]
} else {
set path [file normalize [file dirname $v(fileName)]]
set pathlist [file split $path]
set path [eval file join [lreplace $pathlist end end $v(labdir)]]
}
}
set fileName [tk_getOpenFile -title "Load Transcription" -initialfile $file \
-initialdir $path -defaultextension $v(labext)]
if {$fileName == ""} return
if {[string compare $path [file dirname $fileName]] != 0} {
set Info(path) [file dirname $fileName]
}
openTranscriptionFile $w $pane $fileName labelfile
$w _redrawPane $pane
}
proc trans::getOpenTextLabelFile {w pane} {
variable Info
upvar [namespace current]::${pane}::var v
if {$v(changed)} {
if {[string match no [tk_messageBox -message "You have unsaved changes.\nDo you really want to continue?" -type yesno -icon question]]} {
return
}
}
set file [file tail $v(fileName)]
if {$Info(path) != ""} {
set path $Info(path)
} else {
if {$v(labdir) == ""} {
set path [file dirname $v(fileName)]
} else {
set path [file normalize [file dirname $v(fileName)]]
set pathlist [file split $path]
set path [eval file join [lreplace $pathlist end end $v(labdir)]]
}
}
set fileName [tk_getOpenFile -title "Load Text Labels" -initialfile $file \
-initialdir $path -defaultextension $v(labext)]
if {$fileName == ""} return
if {[string compare $path [file dirname $fileName]] != 0} {
set Info(path) [file dirname $fileName]
}
set f [open $fileName]
fconfigure $f -encoding utf-8
set labels [split [read -nonewline $f]]
close $f
set start [expr 0.5 * [$pane cget -maxtime]]
set delta [expr 0.5 * [$pane cget -maxtime] / [llength $labels]]
set i 0
set v(t1,start) 0.0
foreach label $labels {
set v(t1,$i,end) [expr {$start + $i * $delta}]
set v(t1,$i,label) $label
set v(t1,$i,rest) ""
lappend map $i
incr i
}
set v(t1,end) [$pane cget -maxtime]
set v(nLabels) $i
set v(map) $map
set v(header) ""
set v(headerFmt) WaveSurfer
$w _redrawPane $pane
}
proc trans::saveTranscriptionFiles {w pane} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription) && $v(changed)} {
saveTranscriptionFile $w $pane
}
}
}
proc trans::getSaveTranscriptionFile {w pane} {
upvar [namespace current]::${pane}::var v
set file [file tail $v(fileName)]
if {$v(labdir) == ""} {
set path [file dirname $v(fileName)]
} else {
set path [file normalize [file dirname $v(fileName)]]
set pathlist [file split $path]
set path [eval file join [lreplace $pathlist end end $v(labdir)]]
}
set fileName [tk_getSaveFile -title "Save Transcription" -initialfile $file \
-initialdir $path -defaultextension $v(labext)]
if {$fileName == ""} return
set v(fileName) $fileName
set v(labext) [file extension $fileName]
saveTranscriptionFile $w $pane
}
proc trans::addTranscription {w pane args} {
variable Info
upvar [namespace current]::${pane}::var v
array set a [list \
-alignment e \
-labelcolor black \
-boundarycolor black \
-backgroundcolor white \
-extension ".lab" \
-font {Courier 8} \
-format WaveSurfer \
-labeldirectory "" \
-fileencoding "" \
-adjustleftevent Control-l \
-adjustrightevent Control-r \
-playlabelevent Control-space \
-labelmenu {2 7 lab1 lab2 lab3 lab4 lab5 lab6 lab7 lab8} \
-locked 0 \
-quickenter 1 \
-quickentertolerance 20 \
-extendboundaries 0 \
-linkboundaries 0 \
-playhighlight 0 \
]
if {[string match macintosh $::tcl_platform(platform)]} {
set a(-labelmenuevent) Shift-ButtonPress-1
} else {
set a(-labelmenuevent) Shift-ButtonPress-3
}
if {[string match Darwin $::tcl_platform(os)]} {
set a(-labelmenuevent) Shift-ButtonPress-1
set a(-labelmenu) {1 6 lab1 lab2 lab3 lab4 lab5 lab6}
}
if {[string match unix $::tcl_platform(platform)] } {
set a(-font) {Courier 10}
}
array set a $args
set v(alignment) $a(-alignment)
set v(labColor) $a(-labelcolor)
set v(bdColor) $a(-boundarycolor)
set v(bgColor) $a(-backgroundcolor)
set v(labext) .[string trim $a(-extension) .]
set v(font) $a(-font)
set v(format) $a(-format)
set v(labdir) $a(-labeldirectory)
set v(encoding) $a(-fileencoding)
set v(menuNcols) [lindex $a(-labelmenu) 0]
set v(menuNrows) [lindex $a(-labelmenu) 1]
set v(labelMenuEvent) $a(-labelmenuevent)
set v(adjustLeftEvent) $a(-adjustleftevent)
set v(adjustRightEvent) $a(-adjustrightevent)
set v(playLabelEvent) $a(-playlabelevent)
set v(locked) $a(-locked)
set v(quickenter) $a(-quickenter)
set v(quicktol) $a(-quickentertolerance)
set v(extBounds) $a(-extendboundaries)
set v(linkBounds) $a(-linkboundaries)
set v(highlight) $a(-playhighlight)
set v(changed) 0
set v(t1,start) 0.0
set v(t1,end) 0.0
set v(nLabels) 0
set v(fileName) ""
set v(lastPos) 0
set v(map) {}
set v(lastmoved) -1
set v(drawTranscription) 1
set v(headerFmt) WaveSurfer
set v(header) ""
list {
set v(lastTag) ""
set v(hidden) ""
}
event add <<LabelMenuEvent>> <$v(labelMenuEvent)>
event add <<AdjustLeftEvent>> <$v(adjustLeftEvent)>
event add <<AdjustRightEvent>> <$v(adjustRightEvent)>
event add <<PlayLabelEvent>> <$v(playLabelEvent)>
for {set i 0} {$i < $v(menuNrows)} {incr i } {
for {set j 0} {$j < $v(menuNcols)} {incr j } {
set v($i$j) [lindex $a(-labelmenu) \
[expr {2 + $v(menuNcols) * $i + $j}]]
}
}
set c [$pane canvas]
list {
foreach tag {text bg bound} {
util::canvasbind $c $tag <<LabelMenuEvent>> \
[namespace code [list labelsMenu $w $pane %X %Y %x %y]]
}
}
util::canvasbind $c bound <B1-Motion> \
[namespace code [list MoveBoundary $w $pane %x]]
util::canvasbind $c bound <ButtonPress-1> ""
bind $c <ButtonPress-2> \
[namespace code [list handleEvents PlayLabel %x %y]]
$c bind bound <Enter> [list $c configure \
-cursor sb_h_double_arrow]
$c bind bound <Leave> [list $c configure -cursor {}]
$c bind text <Enter> [list $c configure -cursor xterm]
$c bind text <Leave> [list $c configure -cursor {}]
util::canvasbind $c text <B1-Motion> [namespace code \
[list textB1Move $w $pane %W %x %y]]
util::canvasbind $c text <ButtonRelease-1> ""
util::canvasbind $c text <ButtonPress-1> [namespace code \
[list textClick $w $pane %W %x %y]]
util::canvasbind $c bg <ButtonPress-1> [namespace code \
[list boxClick $w $pane %W %x %y]]
bind $c <Any-Key> [namespace code [list handleAnyKey $w $pane %W %x %y %A]]
bind $c <BackSpace> [namespace code [list handleBackspace $w $pane %W]]
bind $c <Return> {
%W insert current insert ""
%W focus {}
}
bind $c <Enter> [namespace code [list handleEnterLeave $w $pane 1]]
bind $c <Leave> [namespace code [list handleEnterLeave $w $pane 0]]
bind [winfo toplevel $c] <<AdjustRightEvent>> \
[namespace code [list handleEvents AdjustLabel %x %y right]]
bind [winfo toplevel $c] <<AdjustLeftEvent>> \
[namespace code [list handleEvents AdjustLabel %x %y left]]
util::canvasbind $c text <<AdjustRightEvent>> ""
util::canvasbind $c text <<AdjustLeftEvent>> ""
bind $c <<PlayLabelEvent>> \
[namespace code [list handleEvents PlayLabel %x %y]]
bind [winfo toplevel $c] <<PlayLabelEvent>> \
[namespace code [list handleEvents PlayLabel %x %y]]
bind $c <<Delete>> "[namespace code [list handleDelete $w $pane %W]];break"
bind $c <space> "[namespace code [list handleSpace $w $pane %W]];break"
bind $c <Shift-Control-space> "[namespace code [list FindNextLabel $w $pane]];break"
$c bind text <Key-Right> [namespace code [list handleKeyRight $w $pane %W]]
$c bind text <Key-Left> [namespace code [list handleKeyLeft $w $pane %W]]
if {[$w getInfo fileName] != ""} {
openTranscriptionFile $w $pane [$w getInfo fileName] soundfile
# redraw $w $pane
}
if {$::tcl_version > 8.2} {
if $v(locked) {
$c configure -state disabled
} else {
$c configure -state normal
}
}
# If the label file is longer than any current displayed pane, update them all
if {[info exists v(t1,end)]} {
if {$v(t1,end) > [$pane cget -maxtime]} {
$w _redraw
}
}
}
proc trans::handleEvents {proc args} {
if {![info exists ::trpane]} {
return
}
if {[namespace which -variable \
[namespace current]::${::trpane}::var] == ""} return
upvar [namespace current]::${::trpane}::var v
if {[info exists v(cursorInPane)]} {
if {$v(cursorInPane)} {
eval $proc $::trw $::trpane $args
}
}
}
proc trans::handleEnterLeave {w pane arg} {
upvar [namespace current]::${pane}::var v
set v(cursorInPane) $arg
}
proc trans::activateInput {w pane state} {
variable Info
upvar [namespace current]::${pane}::var v
if {[info exists Info($w,active)]} {
if {$state == 1} {
set Info($w,active) $pane
[$pane yaxis] configure -relief solid
[$pane canvas] configure -relief solid
if {$v(extBounds)} {
drawExtendedBoundaries $w $pane
}
}
foreach p [$w _getPanes] {
if {$state == 0 || [string compare $p $pane]} {
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
[$p yaxis] configure -relief flat
[$p canvas] configure -relief flat
}
}
}
}
}
}
proc trans::state {w state} {
variable Info
if {[info exists Info($w,active)]} {
if {$Info($w,active) != ""} {
activateInput $w $Info($w,active) $state
set c [$Info($w,active) canvas]
if {$state} {
boxClick $w $Info($w,active) $c 0 0
}
}
}
}
proc trans::labelsMenu {w pane X Y x y} {
upvar [namespace current]::${pane}::var v
set m $w.popup
if {[winfo exists $m]} {destroy $m}
menu $m -tearoff 0
$m add command -label "Play Label" \
-command [namespace code [list PlayLabel $w $pane $x $y]]
$m add command -label "Insert Label" \
-command [namespace code [list InsertLabel $w $pane $x $y]]
$m add command -label "Select Label" \
-command [namespace code [list SelectLabel $w $pane $x $y]]
$m add command -label "Align Label" \
-command [namespace code [list AlignLabel $w $pane $x $y]]
$m add command -label "Browse..." \
-command [namespace code [list browse $w $pane]]
$m add command -label "Convert..." \
-command [namespace code [list convert $w $pane]]
$m add separator
$m add command -label "Delete Label" \
-command [namespace code [list DeleteLabel $w $pane $x $y]]
for {set j 0} {$j < $v(menuNcols)} {incr j } {
for {set i 0} {$i < $v(menuNrows)} {incr i } {
if {$i==0} {set cb 1} else {set cb 0}
$m add command -label [subst $v($i$j)] -columnbreak $cb \
-command [namespace code [list InsertLabel $w $pane $x $y \
[subst $v($i$j)]]] \
-font $v(font)
}
}
if {[string match macintosh $::tcl_platform(platform)]} {
tk_popup $w.popup $X $Y 0
} else {
tk_popup $w.popup $X $Y
}
}
proc trans::textClick {w pane W x y} {
upvar [namespace current]::${pane}::var v
set ::trpane $pane
set ::trw $w
set c [$pane canvas]
focus $W
$W focus current
$W icursor current @[$W canvasx $x],[$W canvasy $y]
$W select clear
$W select from current @[$W canvasx $x],[$W canvasy $y]
set tagno [lindex [$c gettags current] 0]
activateInput $w $pane 1
set i [lsearch -exact $v(map) $tagno]
if {$i == -1} return
set start [GetStartByIndex $w $pane $i]
set end $v(t1,$tagno,end)
set len [expr $end - $start]
$w messageProc \
"$v(t1,$tagno,label) ($tagno) start: $start end: $end length: $len"
}
proc trans::textB1Move {w pane W x y} {
# clear widget selection before selecting any text
foreach {start end} [$w cget -selection] break
$w configure -selection [list $start $start]
$W select to current @[$W canvasx $x],[$W canvasy $y]
}
proc trans::boxClick {w pane W x y} {
upvar [namespace current]::${pane}::var v
set ::trpane $pane
set ::trw $w
set c [$pane canvas]
focus $W
$W focus hidden
set cx [$c canvasx $x]
set t [$pane getTime $cx]
$w configure -selection [list $t $t]
activateInput $w $pane 1
set v(clicked) 1
}
proc trans::handleAnyKey {w pane W x y A} {
upvar [namespace current]::${pane}::var v
if {[string length $A] == 0} return
if {[string is print $A] == 0} return
set c [$pane canvas]
if {[$W focus] != $v(hidden)} {
set tag [$W focus]
catch {$W dchars $tag sel.first sel.last}
$W insert $tag insert $A
SetLabelText $w $pane [lindex [$c gettags $tag] 0] \
[$c itemcget $tag -text]
} else {
if {$v(quickenter) == 0} return
set dx [expr {abs($v(lastPos) - $x)}]
if {$v(quicktol) > $dx && $v(clicked) == 0} {
set tagno $v(lastTag)
append v(t1,$tagno,label) $A
$c itemconf lab$v(lastTag) -text $v(t1,$tagno,label)
} else {
set v(lastTag) [InsertLabel $w $pane $x $y $A]
if {$v(lastTag) == ""} return
set v(lastPos) $x
set v(clicked) 0
}
}
changed $w $pane
}
proc trans::handleDelete {w pane W} {
set c [$pane canvas]
if {[$W focus] != {}} {
set tag [$W focus]
if {![catch {$W dchars $tag sel.first sel.last}]} {
return
}
$W dchars $tag insert
SetLabelText $w $pane [lindex [$c gettags $tag] 0] \
[$c itemcget $tag -text]
changed $w $pane
}
}
proc trans::handleBackspace {w pane W} {
set c [$pane canvas]
if {[$W focus] != {}} {
set tag [$W focus]
if {![catch {$W dchars $tag sel.first sel.last}]} {
return
}
set ind [expr {[$W index $tag insert]-1}]
if {$ind >= 0} {
$W icursor $tag $ind
$W dchars $tag insert
SetLabelText $w $pane [lindex [$c gettags $tag] 0] \
[$c itemcget $tag -text]
changed $w $pane
}
}
}
proc trans::handleSpace {w pane W} {
set c [$pane canvas]
if {[$W focus] != {}} {
$W select clear
$W insert [$W focus] insert _
SetLabelText $w $pane [lindex [$c gettags [$W focus]] 0] \
[$c itemcget [$W focus] -text]
}
}
proc trans::handleKeyRight {w pane W} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
if {[$W focus] != {}} {
$W select clear
set __index [$W index [$W focus] insert]
$W icursor [$W focus] [expr {$__index + 1}]
if {$__index == [$W index [$W focus] insert]} {
set ti [lindex [$c gettags [$W focus]] 0]
set i [lsearch -exact $v(map) $ti]
set __focus [lindex $v(map) [expr {$i+1}]]
$W focus lab$__focus
$W icursor lab$__focus 0
while {$width * [lindex [$c xview] 1]-10 < \
[lindex [$W coords [$W focus]] 0] && [lindex [$c xview] 1] < 1} {
$w xscroll scroll 1 unit
}
}
}
}
proc trans::handleKeyLeft {w pane W} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
if {[$W focus] != {}} {
$W select clear
set __index [$W index [$W focus] insert]
$W icursor [$W focus] [expr {[$W index [$W focus] insert] - 1}]
if {$__index == [$W index [$W focus] insert]} {
set ti [lindex [$c gettags [$W focus]] 0]
set i [lsearch -exact $v(map) $ti]
set __focus [lindex $v(map) [expr {$i-1}]]
$W focus lab$__focus
$W icursor lab$__focus end
while {$width * [lindex [$c xview] 0] +10 > \
[lindex [$W coords [$W focus]] 0] && [lindex [$c xview] 0] > 0} {
$w xscroll scroll -1 unit
}
}
}
}
proc trans::openFile {w soundFileName} {
variable Info
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription)} {
openTranscriptionFile $w $pane [$w getInfo fileName] soundfile
}
}
return 0
}
proc trans::saveFile {w soundFileName} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription) && $v(changed)} {
saveTranscriptionFile $w $pane
}
}
return 0
}
proc trans::openTranscriptionFile {w pane fn type} {
variable Info
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription) == 0} return
}
set fileName ""
if {[string match soundfile $type]} {
set path [file normalize [file dirname $fn]]
set pathlist [file split $path]
set rootname [file tail [file rootname $fn]]
set name $rootname.[string trim $v(labext) .]
# Try to locate the corresponding label file
if {$v(labdir) != ""} {
# Try the following directories in order
# 1. try to locate file in specified label file directory
# 2. try 'sound file path'/../'specified dir'
# 3. look in current directory
# 4. look in same directory as sound file
if {[file readable [file join $v(labdir) $name]]} {
set fileName [file join $v(labdir) $name]
} elseif {[file readable [eval file join [lreplace $pathlist end end $v(labdir)] $name]]} {
set fileName [eval file join [lreplace $pathlist end end $v(labdir)] $name]
}
}
if {$fileName == ""} {
if {[file readable $name]} {
set fileName $name
} elseif {[file readable [file join $path $name]]} {
set fileName [file join $path $name]
} else {
set fileName $name
}
}
} else {
set fileName $fn
}
# This filename should be correct, remember it
set v(fileName) $fileName
set v(nLabels) 0
set v(map) {}
set v(labext) [file extension $fileName]
foreach {format loadProc saveProc} $Info(formats) {
if {[string compare $format $v(format)] == 0} {
set res [[namespace parent]::$loadProc $w $pane]
if {$res != ""} {
$w messageProc $res
set v(changed) 0
return
}
}
}
}
proc trans::saveTranscriptionFile {w pane} {
variable Info
upvar [namespace current]::${pane}::var v
set fn $v(fileName)
set strip_fn [file tail [file rootname $fn]]
if {$strip_fn == ""} {
set strip_fn [file tail [file rootname [$w getInfo fileName]]]
}
set path [file dirname $fn]
set v(fileName) [file join $path $strip_fn.[string trim $v(labext) .]]
set fn $v(fileName)
catch {file copy $fn $fn~}
foreach {format loadProc saveProc} $Info(formats) {
if {[string compare $format $v(format)] == 0} {
set res [[namespace parent]::$saveProc $w $pane]
if {$res != ""} {
$w messageProc $res
return
}
}
}
set v(changed) 0
return 0
}
proc trans::needSave {w pane} {
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
if {$v(changed)} {
return 1
}
}
}
return 0
}
proc trans::redraw {w pane} {
upvar [namespace current]::${pane}::var v
if {!$v(drawTranscription)} return
set c [$pane canvas]
$c delete tran
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var ov
upvar wsurf::dataplot::${otherpane}::var dv
if {$ov(drawWaveform) || $ov(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
$othercanvas delete tran$pane
}
}
_redraw $w $pane $c 0 0
# boxClick $w $pane $c 0 0
}
proc trans::_redraw {w pane c x y} {
upvar [namespace current]::${pane}::var v
set progressproc [$w cget -progressproc]
if {$progressproc != "" && $v(nLabels) > 0} {
# $progressproc "Creating labels" 0.0
}
set height [$pane cget -height]
set v(height) $height
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
set ascent [font metrics $v(font) -ascent]
set v(ascent) $ascent
$c configure -bg $v(bgColor)
[$pane yaxis] delete ext
set vc [$pane yaxis]
set yw [winfo width $vc]
if {$::tcl_version > 8.2 && [string match disabled [$c cget -state]]} {
[$pane yaxis] create text [expr {$yw/2}] [expr {$height/2}] \
-text L:$v(labext) \
-font $v(font) -tags ext \
-fill $v(labColor)
} else {
[$pane yaxis] create text [expr {$yw/2}] [expr {$height/2}] \
-text $v(labext) \
-font $v(font) -tags ext \
-fill $v(labColor)
}
if {$v(nLabels) == 0} {
set slen [[$w cget -sound] length -unit seconds]
set endx [$pane getCanvasX $slen]
$c create rectangle [expr {$x+0}] $y \
[expr {$x+$endx}] [expr {$y+$height-4}] -outline "" \
-tags [list gEnd obj bg tran] -fill $v(bgColor)
set v(hidden) [$c create text [expr {$x-100}] [expr {$y+10}] \
-text "" -tags [list hidden tran]]
return 0
} else {
set start 0
set end 0
set label ""
for {set i [expr $v(nLabels)-1]} {$i >= 0} {incr i -1} {
set ind [lindex $v(map) $i]
if {$i == 0} {
set start $v(t1,start)
} else {
set ind2 [lindex $v(map) [expr {$i - 1}]]
set start $v(t1,$ind2,end)
}
set end $v(t1,$ind,end)
set label $v(t1,$ind,label)
set lx [$pane getCanvasX $start]
set rx [$pane getCanvasX $end]
if {$lx >= 0 && $lx <= $width} {
#DrawLabel $w $pane $c $ind $i $x $y $lx $rx $label
set tx [ComputeTextPosition $w $pane $lx $rx]
$c create rectangle [expr {$x+$lx}] $y \
[expr {$x+$rx}] [expr {$y+$height-4}] -outline "" \
-tags [list g$ind obj bg tran] -fill $v(bgColor)
$c create text [expr {$x+$tx}] [expr {$y+$ascent}] -text $label\
-font $v(font) -anchor $v(alignment)\
-tags [list $ind obj text lab$ind tran] \
-fill $v(labColor)
$c create line [expr {$x+$rx}] $y [expr {$x+$rx}] [expr {$y+$height}] \
-tags [list b$ind obj bound tran topmost] -fill $v(bdColor)
}
if {$progressproc != "" && $i % 100 == 99} {
# $progressproc "Creating labels" [expr double($v(nLabels)-$i)/$v(nLabels)]
}
}
set start $v(t1,start)
set sx [$pane getCanvasX $start]
$c create rectangle [expr {$x+0}] $y \
[expr {$x+$sx}] [expr {$y+$height-4}] -outline "" \
-tags [list gStart obj bg tran] -fill $v(bgColor)
$c create line [expr {$x+$sx}] $y [expr {$x+$sx}] [expr {$y+$height}] \
-tags [list bStart obj bound tran topmost] -fill $v(bdColor)
set slen [[$w cget -sound] length -unit seconds]
set endx [$pane getCanvasX $slen]
$c create rectangle [expr {$x+$rx}] $y \
[expr {$x+$endx}] [expr {$y+$height-4}] -outline "" \
-tags [list gEnd obj bg tran] -fill $v(bgColor)
set prev [lindex $v(map) end]
$c lower gEnd g$prev
}
set v(hidden) [$c create text [expr {$x-100}] [expr {$y+10}] \
-text "" -tags [list hidden tran]]
if {$v(extBounds)} {
drawExtendedBoundaries $w $pane
}
if {$progressproc != ""} {
# $progressproc "Creating labels" 1.0
}
return $height
}
proc trans::drawExtendedBoundaries {w pane} {
upvar [namespace current]::${pane}::var v
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var ov
upvar wsurf::dataplot::${otherpane}::var dv
if {$ov(drawWaveform) || $ov(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
$othercanvas delete tran$pane
}
}
set height [$pane cget -height]
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
if {$v(nLabels) > 0} {
set start 0
set end 0
set label ""
for {set i [expr $v(nLabels)-1]} {$i >= 0} {incr i -1} {
set ind [lindex $v(map) $i]
if {$i == 0} {
set start $v(t1,start)
} else {
set ind2 [lindex $v(map) [expr {$i - 1}]]
set start $v(t1,$ind2,end)
}
set end $v(t1,$ind,end)
set label $v(t1,$ind,label)
set lx [$pane getCanvasX $start]
set rx [$pane getCanvasX $end]
if {$lx >= 0 && $lx <= $width} {
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var av
upvar wsurf::dataplot::${otherpane}::var dv
if {$av(drawWaveform) || $av(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
set height [$otherpane cget -height]
$othercanvas create line $rx 0 $rx \
$height -tags [list b$ind$pane obj bound tran$pane] \
-fill $v(bdColor)
}
}
}
}
}
}
proc trans::DrawLabel {w pane c tagno i x y lx rx label} {
upvar [namespace current]::${pane}::var v
# set ascent [font metrics $v(font) -ascent]
# set height [$pane cget -height]
set ascent $v(ascent)
set height $v(height)
set tx [ComputeTextPosition $w $pane $lx $rx]
$c create rectangle [expr {$x+$lx}] $y \
[expr {$x+$rx}] [expr {$y+$height-4}] -outline "" \
-tags [list g$tagno obj bg tran] -fill $v(bgColor)
$c create text [expr {$x+$tx}] [expr {$y+$ascent}] -text $label\
-font $v(font) -anchor $v(alignment)\
-tags [list $tagno obj text lab$tagno tran] \
-fill $v(labColor)
$c create line [expr {$x+$rx}] $y [expr {$x+$rx}] [expr {$y+$height}] \
-tags [list b$tagno obj bound tran topmost] -fill $v(bdColor)
if {$i > 0} {
set prev [lindex $v(map) [expr {$i-1}]]
$c lower g$tagno g$prev
$c lower lab$tagno g$prev
$c lower b$tagno g$prev
} else {
$c lower g$tagno gStart
$c lower lab$tagno gStart
$c lower b$tagno gStart
}
if {$v(extBounds)} {
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var av
upvar wsurf::dataplot::${otherpane}::var dv
if {$av(drawWaveform) || $av(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
set height [$otherpane cget -height]
$othercanvas create line $rx 0 $rx \
$height -tags [list b$tagno obj bound tran$pane] -fill $v(bdColor)
}
}
}
}
proc trans::isLabel {tags} {
expr [string compare [lindex $tags 2] bg] == 0 || \
[string compare [lindex $tags 2] text] == 0
}
proc trans::GetStartByIndex {w pane i} {
upvar [namespace current]::${pane}::var v
if {$i <= 0 || $i == "Start"} {
return $v(t1,start)
} else {
set ind [lindex $v(map) [expr $i-1]]
return $v(t1,$ind,end)
}
}
proc trans::PlaceLabel {w pane tagno coords start end} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
if {$tagno != "Start"} {
# Place background and boundary
$c coords b$tagno $end [lindex $coords 1] $end [lindex $coords 3]
$c coords g$tagno $start [lindex $coords 1] $end [expr [lindex $coords 3]-4]
# Place label text
set tx [ComputeTextPosition $w $pane $start $end]
$c coords lab$tagno $tx [lindex [$c coords lab$tagno] 1]
} else {
$c coords b$tagno $end [lindex $coords 1] $end [lindex $coords 3]
$c coords g$tagno 0 [lindex $coords 1] $end [expr [lindex $coords 3]-4]
}
if {$v(extBounds)} {
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var av
upvar wsurf::dataplot::${otherpane}::var dv
if {$av(drawWaveform) || $av(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
set height [$otherpane cget -height]
$othercanvas coords b$tagno$pane $end 0 $end $height
}
}
}
}
proc trans::getBounds {w pane} {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription)} {
list 0 0 $v(t1,end) 0
} else {
list
}
}
proc trans::MoveBoundary {w pane x} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set s [$w cget -sound]
set coords [$c coords current]
set xc [$c canvasx $x]
if {$xc < 0} { set xc 0 }
set tagno [string trim [lindex [$c gettags current] 0] b]
set i [lsearch -exact $v(map) $tagno]
# Logic which prevents a boundary to be moved past its neighbor
set h [lindex $v(map) [expr {$i-1}]]
set j [lindex $v(map) [expr {$i+1}]]
set px 0
set nx [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
set pb [$c find withtag b$h]
set nb [$c find withtag b$j]
if {$pb != ""} { set px [lindex [$c coords $pb] 0]}
if {$nb != ""} { set nx [lindex [$c coords $nb] 0]}
if {$xc <= $px} { set xc [expr {$px + 1}] }
if {$nx <= $xc} { set xc [expr {$nx - 1}] }
set start [$pane getCanvasX [GetStartByIndex $w $pane $i]]
# Update time
if {$i == -1} {
set v(t1,start) [$pane getTime $xc]
} else {
set this [lindex $v(map) $i]
set oldTime $v(t1,$this,end)
set v(t1,$this,end) [$pane getTime $xc]
}
# Place this label
PlaceLabel $w $pane $tagno $coords $start $xc
# Place next label
PlaceNextLabel $w $pane $i $xc
if {$v(linkBounds)} {
foreach otherpane [$w _getPanes] {
upvar [namespace current]::${otherpane}::var ov
if {$otherpane != $pane && $ov(drawTranscription) && \
[info exists oldTime]} {
foreach tag $ov(map) {
if {$ov(t1,$tag,end) == $oldTime} {
set ov(t1,$tag,end) [$pane getTime $xc]
PlaceLabel $w $otherpane $tag $coords $start $xc
break
}
}
}
}
}
if {$v(lastmoved) != $i} {
changed $w $pane
if {$tagno == "Start"} {
# wsurf::PrepareUndo "set [namespace current]::var(t1,start) \[list $v(t1,start)\]" ""
} else {
# wsurf::PrepareUndo "set [namespace current]::var(t1,$tagno,end) \[list $v(t1,$tagno,end)\]" ""
}
set v(lastmoved) $i
}
vtcanvas::motionEvent $pane $x 0
}
proc trans::SetLabelText {w pane tagno label} {
upvar [namespace current]::${pane}::var v
$w messageProc [format "Transcription - %s" $label]
set v(t1,$tagno,label) $label
}
proc trans::InsertLabel {w pane x y {label ""}} {
upvar [namespace current]::${pane}::var v
set s [$w cget -sound]
set c [$pane canvas]
set cx [$c canvasx $x]
set t [$pane getTime $cx]
set tags [$c gettags [$c find closest [$c canvasx $x] [$c canvasy $y]]]
if {[isLabel $tags]} {
set tagno [string trim [lindex $tags 0] g]
if {$tagno == "End"} {
# set i $v(nLabels)
set i 0
foreach ind $v(map) {
if {$t < $v(t1,$ind,end)} break
incr i
}
} else {
set i [lsearch -exact $v(map) $tagno]
}
} else {
set i 0
foreach ind $v(map) {
if {$t < $v(t1,$ind,end)} break
incr i
}
}
# Create label with a randomly chosen tag number
set n [clock clicks]
set v(t1,$n,end) $t
set v(t1,$n,label) $label
set v(t1,$n,rest) ""
set v(map) [linsert $v(map) $i $n]
incr v(nLabels)
# Update start time if new label was inserted first
if {$i < 0} {
set v(t1,start) 0
set co [$c coords bStart]
$c coords bStart 0 [lindex $co 1] 0 [lindex $co 3]
set co [$c coords gStart]
$c coords gStart 0 [lindex $co 1] 0 [lindex $co 3]
set start 0
} else {
set start [$pane getCanvasX [GetStartByIndex $w $pane $i]]
}
# Draw inserted label
DrawLabel $w $pane $c $n $i 0 0 $start $cx $label
# Place next label
if {$i < 0} { incr i }
PlaceNextLabel $w $pane $i $cx
# Display cursor if label is empty
if {$label==""} {
focus [$pane canvas]
[$pane canvas] focus lab$n
[$pane canvas] icursor lab$n @[$c canvasx $x],[$c canvasy $y]
}
changed $w $pane
return $n
}
proc trans::DeleteLabel {w pane x y} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set tags [$c gettags [$c find closest [$c canvasx $x] [$c canvasy $y]]]
if {[isLabel $tags] || [string compare [lindex $tags 2] bound] == 0} {
set tagno [string trim [lindex $tags 0] gb]
set i [lsearch -exact $v(map) $tagno]
if {$i == -1} return
# Delete everything related to this label
unset v(t1,$tagno,label)
unset v(t1,$tagno,end)
unset v(t1,$tagno,rest)
set v(map) [lreplace $v(map) $i $i]
incr v(nLabels) -1
$c delete b$tagno lab$tagno g$tagno
if {$v(extBounds)} {
foreach otherpane [$w _getPanes] {
upvar wsurf::analysis::${otherpane}::var av
upvar wsurf::dataplot::${otherpane}::var dv
if {$av(drawWaveform) || $av(drawSpectrogram) || $dv(drawDataPlot)} {
set othercanvas [$otherpane canvas]
$othercanvas delete b$tagno$pane
}
}
}
# Place previous label box
set prev [lindex $v(map) [expr {$i-1}]]
if {$prev != ""} {
set end [lindex [$c coords g$prev] 2]
} else {
set end [$pane getCanvasX $v(t1,start)]
set prev 0
}
set iprev [lsearch -exact $v(map) $prev]
PlaceNextLabel $w $pane $iprev $end
changed $w $pane
}
}
proc trans::AdjustLabel {w pane x y boundary} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set xc [$c canvasx $x]
set t [$pane getTime $xc]
set tags [$c gettags [$c find closest $xc [$c canvasy $y]]]
if {[isLabel $tags]} {
set tagno [string trim [lindex $tags 0] g]
set i [lsearch -exact $v(map) $tagno]
} else {
set i 0
foreach ind $v(map) {
if {$t < $v(t1,$ind,end)} break
incr i
}
set tagno [lsearch -exact $v(map) $i]
}
if {$i == $v(nLabels)} return
if {$tagno != "End" && [string match left $boundary]} {
incr i -1
set tagno [lindex $v(map) $i]
}
if {$tagno == "End"} return
if {$tagno != ""} {
set v(t1,$tagno,end) $t
}
if {$i < 0} {
set v(t1,start) $t
set co [$c coords bStart]
set sx [$pane getCanvasX $t]
$c coords bStart $sx [lindex $co 1] $sx [lindex $co 3]
$c coords gStart 0 [lindex $co 1] $sx [lindex $co 3]
}
set start [$pane getCanvasX [GetStartByIndex $w $pane $i]]
# Place this label
set co [$c coords b$tagno]
PlaceLabel $w $pane $tagno $co $start $xc
# Place next label
PlaceNextLabel $w $pane $i $xc
changed $w $pane
$w messageProc [format "Transcription - %s" [$w formatTime $t]]
}
proc trans::PlayLabel {w pane x y} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set tags [$c gettags [$c find closest [$c canvasx $x] [$c canvasy $y]]]
if {[isLabel $tags]} {
set tagno [string trim [lindex $tags 0] g]
set i [lsearch -exact $v(map) $tagno]
if {$i == -1} return
} else {
set i 0
set cx [$c canvasx $x]
set t [$pane getTime $cx]
foreach ind $v(map) {
if {$t < $v(t1,$ind,end)} break
incr i
}
}
set start [GetStartByIndex $w $pane $i]
set this [lindex $v(map) $i]
if {$this == ""} return
set end $v(t1,$this,end)
$w play $start $end
}
proc trans::SelectLabel {w pane x y} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set tags [$c gettags [$c find closest [$c canvasx $x] [$c canvasy $y]]]
if {[isLabel $tags]} {
set tagno [string trim [lindex $tags 0] g]
set i [lsearch -exact $v(map) $tagno]
if {$i == -1} return
set start [GetStartByIndex $w $pane $i]
set end $v(t1,$tagno,end)
$w configure -selection [list $start $end]
}
}
proc trans::AlignLabel {w pane x y} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
set tags [$c gettags [$c find closest [$c canvasx $x] [$c canvasy $y]]]
if {[isLabel $tags]} {
set tagno [string trim [lindex $tags 0] g]
set i [lsearch -exact $v(map) $tagno]
if {$i == -1} return
# Get current selection
foreach {start end} [$w cget -selection] break
if {$start == $end} return
# Validate that selection and label overlap, otherwise generate warning msg
set ostart [GetStartByIndex $w $pane $i]
set oend $v(t1,$tagno,end)
if {$start >= $oend || $end <= $ostart} {
tk_messageBox -message "Label and selection must overlap!"
return
}
# Update boundaries according to current selection
if {$i == 0} {
set v(t1,start) $start
} else {
set ind [lindex $v(map) [expr $i-1]]
set v(t1,$ind,end) $start
}
set v(t1,$tagno,end) $end
$w _redrawPane $pane
}
}
proc trans::FindNextLabel {w pane} {
upvar [namespace current]::${pane}::var v
foreach {start end} [$w cget -selection] break
set i 0
foreach ind $v(map) {
if {$end < $v(t1,$ind,end)} break
incr i
}
set tagno [lsearch -exact $v(map) $i]
if {$tagno == -1} return
set start [GetStartByIndex $w $pane $i]
set end $v(t1,$tagno,end)
$w configure -selection [list $start $end]
set s [$w cget -sound]
set length [$s length -unit seconds]
$w xscroll moveto [expr {($start-1.0)/$length}]
$w play $start $end
set delay [expr 500 + int(1000 * ($end - $start))]
after $delay [namespace code [list FindNextLabel $w $pane]]
}
proc trans::ComputeTextPosition {w pane start end} {
upvar [namespace current]::${pane}::var v
if {$v(alignment) == "c"} {
return [expr {($start+$end)/2}]
} elseif {$v(alignment) == "w"} {
return [expr {$start + 2}]
} else {
return [expr {$end - 2}]
}
}
proc trans::PlaceNextLabel {w pane index pos} {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
incr index
set next [lindex $v(map) $index]
if {$next == ""} {
set next End
set co [$c coords g$next]
$c coords g$next $pos [lindex $co 1] [lindex $co 2] [lindex $co 3]
} else {
set co [$c coords b$next]
$c coords g$next $pos [lindex $co 1] [lindex $co 2] [expr [lindex $co 3]-4]
# $c itemconf g$next -fill yellow
set xc [ComputeTextPosition $w $pane $pos [lindex $co 2]]
$c coords lab$next $xc [lindex [$c coords lab$next] 1]
}
}
proc trans::print {w pane c x y} {
upvar [namespace current]::${pane}::var v
upvar wsurf::analysis::${pane}::var ov
upvar wsurf::dataplot::${pane}::var dv
if {$ov(drawWaveform) || $ov(drawSpectrogram) || $dv(drawDataPlot)} {
foreach otherpane [$w _getPanes] {
upvar wsurf::trans::${otherpane}::var tv
if {[info exists tv(extBounds)] && $tv(extBounds)} {
set drawExtBounds 1
break;
}
}
}
if {[info exists drawExtBounds]} {
set height [$pane cget -height]
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
set yAxisCanvas [$pane yaxis]
set yAxisWidth [winfo width $yAxisCanvas]
if {$tv(nLabels) > 0} {
set start 0
set end 0
set label ""
for {set i [expr $tv(nLabels)-1]} {$i >= 0} {incr i -1} {
set ind [lindex $tv(map) $i]
if {$i == 0} {
set start $tv(t1,start)
} else {
set ind2 [lindex $tv(map) [expr {$i - 1}]]
set start $tv(t1,$ind2,end)
}
set end $tv(t1,$ind,end)
set label $tv(t1,$ind,label)
set lx [$pane getCanvasX $start]
set rx [$pane getCanvasX $end]
if {$lx >= 0 && $lx <= $width} {
$c create line [expr {$rx+$yAxisWidth}] $y \
[expr {$rx+$yAxisWidth}] [expr {$y+$height}] \
-tags [list b$ind$pane obj bound tran$pane print tmpPrint] \
-fill $tv(bdColor)
}
}
}
}
if {!$v(drawTranscription)} return
$c raise bound
set yAxisCanvas [$pane yaxis]
set yAxisWidth [winfo width $yAxisCanvas]
set h [$pane cget -height]
set width [expr {[$pane cget -maxtime] * [$pane cget -pixelspersecond]}]
$c create rectangle $yAxisWidth $y \
[expr {$x+$width+$yAxisWidth}] [expr {$y+$h}] \
-tags print -outline black
_redraw $w $pane $c $yAxisWidth $y
}
proc trans::cursorMoved {w pane time value} {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription)} {
$w messageProc \
[format "%s: %s | $v(labelMenuEvent): Label menu" $v(fileName) [$w formatTime $time]]
}
}
proc trans::soundChanged {w flag} {
set s [$w cget -sound]
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription)} {
$w _redrawPane $pane
}
}
}
proc trans::propertyPane {w pane} {
if {$pane==""} return
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription)} {
list Trans1 [namespace code drawPage1] \
Trans2 [namespace code drawPage2]
}
}
proc trans::applyProperties {w pane} {
if {[string match *wavebar $pane]} return
variable Info
upvar [namespace current]::${pane}::var v
if {[info exists v(drawTranscription)]} {
if {$v(drawTranscription)} {
foreach var {format alignment labext labdir encoding \
labColor bdColor bgColor \
font menuNrows menuNcols labelMenuEvent adjustLeftEvent \
adjustRightEvent playLabelEvent locked quickenter quicktol \
extBounds linkBounds highlight} {
if {[string compare $v(t,$var) $v($var)] !=0} {
if [string match labelMenuEvent $var] {
event delete <<LabelMenuEvent>> <$v($var)>
event add <<LabelMenuEvent>> <$v(t,$var)>
}
if [string match adjustLeftEvent $var] {
event delete <<AdjustLeftEvent>> <$v($var)>
event add <<AdjustLeftEvent>> <$v(t,$var)>
}
if [string match adjustRightEvent $var] {
event delete <<AdjustRightEvent>> <$v($var)>
event add <<AdjustRightEvent>> <$v(t,$var)>
}
if [string match playLabelEvent $var] {
event delete <<PlayLabelEvent>> <$v($var)>
event add <<PlayLabelEvent>> <$v(t,$var)>
}
if {$::tcl_version > 8.2 && [string match locked $var] == 1} {
set c [$pane canvas]
if $v(t,$var) {
$c configure -state disabled
} else {
$c configure -state normal
}
}
if {[string match format $var] || \
[string match labext $var] || \
[string match encoding $var] || \
[string match labdir $var]} {
if {$v(changed)} {
if {[string match no [tk_messageBox -message "This operation will cause the transcription to be re-read from disk and you have unsaved changes.\nDo you want to continue?" -type yesno -icon question]]} {
return
}
}
set v($var) $v(t,$var)
openTranscriptionFile $w $pane [$w getInfo fileName] soundfile
set doRedraw 1
}
set v($var) $v(t,$var)
if {[string match labColor $var] || \
[string match bdColor $var] || \
[string match font $var] || \
[string match extBounds $var] || \
[string match alignment $var] || \
[string match bgColor $var]} {
set doRedraw 1
}
if {[string match format $var]} {
set formatChanged 1
}
}
}
if {[info exists doRedraw]} {
$w _redrawPane $pane
}
if {[info exists formatChanged]} {
wsurf::_remeberPropertyPage $w $pane
wsurf::_drawPropertyPages $w $pane
}
for {set i 0} {$i < $v(menuNrows)} {incr i } {
for {set j 0} {$j < $v(menuNcols)} {incr j } {
set v($i$j) $v(t,$i$j)
}
}
}
}
}
proc trans::drawPage1 {w pane path} {
variable Info
upvar [namespace current]::${pane}::var v
foreach f [winfo children $path] {
destroy $f
}
foreach var {format alignment labext labdir encoding \
labColor bdColor bgColor \
font locked quickenter quicktol extBounds linkBounds} {
set v(t,$var) $v($var)
}
pack [frame $path.f1] -anchor w
label $path.f1.l -text "Label file format:" -width 25 -anchor w
foreach {format loadProc saveProc} $Info(formats) {
lappend tmp $format
}
eval tk_optionMenu $path.f1.om [namespace current]::${pane}::var(t,format) \
$tmp
pack $path.f1.l $path.f1.om -side left -padx 3
pack [frame $path.f2] -anchor w
label $path.f2.l -text "Label alignment:" -width 25 -anchor w
tk_optionMenu $path.f2.om [namespace current]::${pane}::var(t,alignment) \
left center right
$path.f2.om.menu entryconfigure 0 -value w
$path.f2.om.menu entryconfigure 1 -value c
$path.f2.om.menu entryconfigure 2 -value e
pack $path.f2.l $path.f2.om -side left -padx 3
stringPropItem $path.f3 "Label filename extension:" 25 16 "" \
[namespace current]::${pane}::var(t,labext)
pack [frame $path.f4] -anchor w
label $path.f4.l -text "Label file path:" -width 25 -anchor w
entry $path.f4.e -textvar [namespace current]::${pane}::var(t,labdir) -wi 16
pack $path.f4.l $path.f4.e -side left -padx 3
if {[info command tk_chooseDirectory] != ""} {
button $path.f4.b -text Choose... \
-command [namespace code [list chooseDirectory $w $pane]]
pack $path.f4.b -side left -padx 3
}
stringPropItem $path.f5 "Label file encoding:" 25 16 "" \
[namespace current]::${pane}::var(t,encoding)
colorPropItem $path.f6 "Label color:" 25 \
[namespace current]::${pane}::var(t,labColor)
colorPropItem $path.f7 "Boundary color:" 25 \
[namespace current]::${pane}::var(t,bdColor)
colorPropItem $path.f8 "Background color:" 25 \
[namespace current]::${pane}::var(t,bgColor)
stringPropItem $path.f9 "Font:" 25 16 "" \
[namespace current]::${pane}::var(t,font)
if {$::tcl_version > 8.2} {
booleanPropItem $path.f10 "Lock transcription" "" \
[namespace current]::${pane}::var(t,locked)
}
booleanPropItem $path.f11 "Quick transcribe" "" \
[namespace current]::${pane}::var(t,quickenter)
stringPropItem $path.f12 "Max cursor movement for current label:" 34 4 \
pixels [namespace current]::${pane}::var(t,quicktol)
booleanPropItem $path.f13 "Extend boundaries into waveform and spectrogram panes" "" \
[namespace current]::${pane}::var(t,extBounds)
booleanPropItem $path.f14 "Move coinciding boundaries in other transcription panes" "" \
[namespace current]::${pane}::var(t,linkBounds)
}
proc trans::confPage {w pane path} {
upvar [namespace current]::${pane}::var v
for {set i 0} {$i < $v(t,menuNrows)} {incr i } {
if {![winfo exists $path.fl$i]} {
pack [frame $path.fl$i] -anchor w
}
for {set j 0} {$j < $v(t,menuNcols)} {incr j } {
if {![winfo exists $path.fl$i.e$j]} {
pack [entry $path.fl$i.e$j -width 6 \
-textvar [namespace current]::${pane}::var(t,$i$j)] -side left
}
$path.fl$i.e$j configure -font $v(t,font)
}
while {[winfo exists $path.fl$i.e$j] == 1} {
destroy $path.fl$i.e$j
incr j
}
}
while {[winfo exists $path.fl$i] == 1} {
destroy $path.fl$i
incr i
}
}
proc trans::chooseDirectory {w pane} {
upvar [namespace current]::${pane}::var v
set dir $v(t,labdir)
if {$dir == ""} {
set dir .
}
set res [tk_chooseDirectory -initialdir $dir -mustexist yes]
if {$res != ""} {
set v(t,labdir) $res
}
}
proc trans::drawPage2 {w pane path} {
upvar [namespace current]::${pane}::var v
foreach f [winfo children $path] {
destroy $f
}
foreach var {adjustLeftEvent adjustRightEvent playLabelEvent labelMenuEvent \
menuNrows menuNcols highlight} {
set v(t,$var) $v($var)
}
for {set i 0} {$i < $v(menuNrows)} {incr i } {
for {set j 0} {$j < $v(menuNcols)} {incr j } {
set v(t,$i$j) $v($i$j)
}
}
booleanPropItem $path.f0 "Highlight labels during playback" "" \
[namespace current]::${pane}::var(t,highlight)
stringPropItem $path.f1 "Adjust left boundary event:" 28 25 "" \
[namespace current]::${pane}::var(t,adjustLeftEvent)
stringPropItem $path.f2 "Adjust right boundary event:" 28 25 "" \
[namespace current]::${pane}::var(t,adjustRightEvent)
stringPropItem $path.f3 "Play label event:" 28 25 "" \
[namespace current]::${pane}::var(t,playLabelEvent)
stringPropItem $path.f4 "Label menu event:" 28 25 "" \
[namespace current]::${pane}::var(t,labelMenuEvent)
pack [frame $path.f5] -anchor w
pack [label $path.f5.l -text "Label menu pane:" -width 25 -anchor w] -padx 3
pack [frame $path.f6] -anchor w
pack [label $path.f6.lc -text "Columns:" -anchor w] -side left -padx 3
pack [entry $path.f6.ec -width 2 -textvar \
[namespace current]::${pane}::var(t,menuNcols)] -side left
pack [label $path.f6.lr -text "Rows:" -anchor w] -side left
pack [entry $path.f6.er -width 2 -textvar \
[namespace current]::${pane}::var(t,menuNrows)] -side left
pack [button $path.f6.b -text Update \
-command [namespace code [list confPage $w $pane $path]]] -side left \
-padx 3
bind $path.f6.ec <Key-Return> [namespace code [list confPage $w $pane $path]]
bind $path.f6.er <Key-Return> [namespace code [list confPage $w $pane $path]]
for {set i 0} {$i < $v(t,menuNrows)} {incr i } {
pack [frame $path.fl$i] -anchor w
for {set j 0} {$j < $v(t,menuNcols)} {incr j } {
pack [entry $path.fl$i.e$j -font $v(t,font) \
-textvar [namespace current]::${pane}::var(t,$i$j) -wi 6] \
-side left
}
}
}
proc trans::getConfiguration {w pane} {
upvar [namespace current]::${pane}::var v
set result {}
if {$pane==""} {return {}}
if {$v(drawTranscription)} {
lappend labmenu $v(menuNcols) $v(menuNrows)
for {set i 0} {$i < $v(menuNrows)} {incr i } {
for {set j 0} {$j < $v(menuNcols)} {incr j } {
if {[info exists v($i$j)]} {
lappend labmenu $v($i$j)
} else {
lappend labmenu \"\"
}
}
}
append result "\$widget trans::addTranscription \$pane\
-alignment $v(alignment)\
-format \"$v(format)\"\
-extension \"$v(labext)\"\
-labelcolor $v(labColor)\
-boundarycolor $v(bdColor)\
-backgroundcolor $v(bgColor)\
-labeldirectory \"$v(labdir)\"\
-fileencoding \"$v(encoding)\"\
-labelmenuevent $v(labelMenuEvent)\
-adjustleftevent $v(adjustLeftEvent)\
-adjustrightevent $v(adjustRightEvent)\
-playlabelevent $v(playLabelEvent)\
-locked $v(locked)\
-quickenter $v(quickenter)\
-quickentertolerance $v(quicktol)\
-extendboundaries $v(extBounds)\
-linkboundaries $v(linkBounds)\
-playhighlight $v(highlight)\
-font \{$v(font)\}"
append result " -labelmenu \{\n"
append result "[lrange $labmenu 0 1]\n"
for {set i 0} {$i < $v(menuNrows)} {incr i } {
append result "[lrange $labmenu [expr 2+$i*$v(menuNcols)] [expr 1+($i+1)*$v(menuNcols)]]\n"
}
append result "\}"
append result "\n"
}
return $result
}
proc trans::cut {w t0 t1} {
set dt [expr {$t1-$t0}]
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if $v(drawTranscription) {
if {[llength $v(map)] == 0} continue
set c [$pane canvas]
set i 0
foreach ind $v(map) {
if {$t0 < $v(t1,$ind,end)} break
incr i
}
# Adjust start time
if {$t0 < $v(t1,start)} {
if {$t1 < $v(t1,start)} {
# Current selection is to the left of start time
set v(t1,start) [expr {$v(t1,start)-$dt}]
} else {
# Left boundary of current selection is to the left of start time
set v(t1,start) $t0
}
}
# Left boundary is new end time for first label
if {$t0 < $v(t1,$ind,end) && \
$t1 > $v(t1,$ind,end)} {
set v(t1,$ind,end) $t0
incr i
set ind [lindex $v(map) $i]
}
set j $i
# Delete labels within the selection
while {$ind != "" && $t1 > $v(t1,$ind,end)} {
# unset v(t1,$ind,label)
# unset v(t1,$ind,end)
# unset v(t1,$ind,rest)
incr i
set ind [lindex $v(map) $i]
}
if {$j <= [expr $i - 1] && $j < [llength $v(map)]} {
set v(map) [lreplace $v(map) $j [expr $i - 1]]
set v(nLabels) [llength $v(map)]
}
# Move all remaining labels $dt to the left
set ind [lindex $v(map) $j]
while {$ind != "" && $t1 < $v(t1,$ind,end)} {
set v(t1,$ind,end) [expr {$v(t1,$ind,end)-$dt}]
incr j
set ind [lindex $v(map) $j]
}
changed $w $pane
$w _redrawPane $pane
}
}
}
proc trans::copy {w t0 t1} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if $v(drawTranscription) {
set c [$pane canvas]
if {[$c focus] != {}} {
set tag [$c focus]
if {[catch {set s [$c index $tag sel.first]}]} return
set e [$c index $tag sel.last]
clipboard append [string range [$c itemcget $tag -text] $s $e]
}
}
}
}
proc trans::paste {w t length} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if $v(drawTranscription) {
set c [$pane canvas]
if {[focus] == $c && [$c focus] != $v(hidden)} {
catch {set cbText [selection get -selection CLIPBOARD]}
if {[info exists cbText] == 0} { return 0 }
$c insert [$c focus] insert [selection get -selection CLIPBOARD]
SetLabelText $w $pane [lindex [$c gettags [$c focus]] 0] \
[$c itemcget [$c focus] -text]
return 1
}
}
}
return 0
list {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if $v(drawTranscription) {
if {[llength $v(map)] == 0} return
set i 0
foreach ind $v(map) {
if {$t < $v(t1,$ind,end)} break
incr i
}
# Adjust start time
if {$t < $v(t1,start)} {
set v(t1,start) [expr {$v(t1,start)+$length}]
}
# Move all remaining labels $length to the left
while {$ind != ""} {
set v(t1,$ind,end) [expr {$v(t1,$ind,end)+$length}]
incr i
set ind [lindex $v(map) $i]
}
$w _redrawPane $pane
}
}}
}
proc trans::find {w pane} {
upvar [namespace current]::${pane}::var v
set p $v(browseTL)
set v(nMatch) 0
$p.f2.list delete 0 end
set i 0
if {$v(matchCase)} {
set nocase ""
} else {
set nocase -nocase
}
foreach ind $v(map) {
if {[eval regexp $nocase $v(pattern) \{$v(t1,$ind,label)\}]} {
if {$i == 0} {
set start $v(t1,start)
} else {
set prev [lindex $v(map) [expr $i-1]]
set start $v(t1,$prev,end)
}
if {[string match *\"* \{$v(t1,$ind,label)\}]} {
set tmp "\{$v(t1,$ind,label):\} $start $v(t1,$ind,end)"
} else {
set tmp "$v(t1,$ind,label): $start $v(t1,$ind,end)"
}
$p.f2.list insert end $tmp
incr v(nMatch)
}
incr i
}
}
proc trans::select {w pane} {
upvar [namespace current]::${pane}::var v
set p $v(browseTL)
set cursel [$p.f2.list curselection]
if {$cursel == ""} return
set start [lindex [$p.f2.list get [lindex $cursel 0]] end-1]
set end [lindex [$p.f2.list get [lindex $cursel end]] end]
$w configure -selection [list $start $end]
set s [$w cget -sound]
set length [$s length -unit seconds]
$w xscroll moveto [expr {$start/$length}]
}
proc trans::findPlay {w pane} {
upvar [namespace current]::${pane}::var v
set p $v(browseTL)
set cursel [$p.f2.list curselection]
if {$cursel != ""} {
set start [lindex [$p.f2.list get [lindex $cursel 0]] end-1]
set end [lindex [$p.f2.list get [lindex $cursel end]] end]
$w play $start $end
}
}
proc trans::browse {w pane} {
upvar [namespace current]::${pane}::var v
regsub -all {\.} $pane _ tmp
set v(browseTL) .browse$tmp
catch {destroy .browse$tmp}
set p [toplevel .browse$tmp]
wm title $p "Browse Labels"
pack [frame $p.f]
pack [entry $p.f.e -textvar [namespace current]::${pane}::var(pattern)]\
-side left
pack [button $p.f.l -text Find \
-command [namespace code [list find $w $pane]]] -side left
pack [ label $p.l -text "Results:"]
pack [ frame $p.f2] -fill both -expand true
pack [ scrollbar $p.f2.scroll -command "$p.f2.list yview"] -side right \
-fill y
listbox $p.f2.list -yscroll "$p.f2.scroll set" -setgrid 1 \
-selectmode extended -height 6 -width 40
pack $p.f2.list -side left -expand true -fill both
pack [checkbutton $p.cb -text "Match case" -anchor w \
-variable [namespace current]::${pane}::var(matchCase)]
pack [ frame $p.f3] -pady 10 -fill x -expand true
pack [ button $p.f3.b1 -bitmap snackPlay \
-command [namespace code [list findPlay $w $pane]]] \
-side left
pack [ button $p.f3.b2 -bitmap snackStop -command "$w stop"] -side left
pack [ button $p.f3.b3 -text Close -command "destroy $p"] -side right
bind $p.f.e <Return> [namespace code [list find $w $pane]]
bind $p.f2.list <ButtonRelease-1> [namespace code [list select $w $pane]]
if {$v(pattern) != ""} {
find $w $pane
}
bind $p.f2.list <Double-Button-1> [namespace code [list findPlay $w $pane]]
focus $p.f.e
}
proc trans::convert {w pane} {
upvar [namespace current]::${pane}::var v
variable Info
regsub -all {\.} $pane _ tmp
set v(convertTL) .convert$tmp
catch {destroy .convert$tmp}
set p [toplevel .convert$tmp]
wm title $p "Convert Transcription File format"
pack [ label $p.l1 -text "Current transcription file format: $v(format)"]
set v(t,format) $v(format)
pack [frame $p.f1] -anchor w
label $p.f1.l -text "New transcription file format:" -anchor w
foreach {format loadProc saveProc} $Info(formats) {
lappend fmtlist $format
}
eval tk_optionMenu $p.f1.om [namespace current]::${pane}::var(t,format) \
$fmtlist
pack $p.f1.l $p.f1.om -side left -padx 3
pack [frame $p.f]
pack [ button $p.f.b1 -text OK -command [namespace code [list doConvert $w $pane]]\n[list destroy $p]] -side left -padx 3
pack [ button $p.f.b2 -text Close -command "destroy $p"] -side left -padx 3
}
proc trans::doConvert {w pane} {
upvar [namespace current]::${pane}::var v
set v(format) $v(t,format)
}
proc trans::play {w} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription) && $v(highlight)} {
set v(playIndex) 0
}
}
after 200 [namespace code [list _updatePlay $w]]
}
proc trans::stop {w} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
if {$v(drawTranscription)} {
after cancel [namespace code [list FindNextLabel $w $pane]]
}
}
}
proc trans::_updatePlay {w} {
if {[winfo exists $w] == 0} {
return
}
if {[$w getInfo isPlaying] == 0} {
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
set c [$pane canvas]
if {$v(drawTranscription)} {
if {$v(highlight) && [info exists v(playIndex)]} {
set ind [lindex $v(map) $v(playIndex)]
if {$ind != ""} {
$c itemconf g$ind -fill $v(bgColor)
}
}
}
}
return
}
set s [$w cget -sound]
foreach pane [$w _getPanes] {
upvar [namespace current]::${pane}::var v
if {$v(drawTranscription) && $v(highlight)} {
set cursorpos [$pane cget -cursorpos]
set c [$pane canvas]
set ind [lindex $v(map) $v(playIndex)]
if {$ind != ""} {
$c itemconf g$ind -fill $v(bgColor)
while (1) {
set ind [lindex $v(map) $v(playIndex)]
if {$ind == ""} return
if {$cursorpos < $v(t1,$ind,end)} break
incr v(playIndex)
}
$c itemconf g$ind -fill [$w cget -cursorcolor]
}
}
}
if {[$w getInfo isPlaying]} {
after 50 [namespace code [list _updatePlay $w]]
}
}
# -----------------------------------------------------------------------------
# !!! experimental
proc trans::regCallback {name callback script} {
variable Info
# puts [info level 0]
if {$callback != "-transcription::transcriptionchangedproc"} {
error "unknown callback \"$callback\""
} else {
set Info(Callback,$name,transChangedProc) $script
}
}
proc trans::changed {w pane} {
# puts [info level 0]([info level -1])
variable Info
upvar [namespace current]::${pane}::var v
set v(changed) 1
foreach key [array names Info Callback,*,transChangedProc] {
puts "invoking callback $key"
$Info($key) $w $pane
}
}
proc trans::SplitSoundFile {w pane} {
upvar [namespace current]::${pane}::var v
set s [$w cget -sound]
foreach ind $v(map) {
set start [expr {int([GetStartByIndex $w $pane $ind] * [$s cget -rate])}]
set end [expr {int($v(t1,$ind,end) * [$s cget -rate])}]
$s write $v(t1,$ind,label).wav -start $start -end $end
}
}