Re-work layering in possibly debatable ways. Sketchy docs in doc/layering.

git-svn-id: svn://localhost/ardour2/branches/3.0@11088 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2011-12-27 01:42:49 +00:00
parent 0082e3364f
commit 6304261b98
41 changed files with 2846 additions and 636 deletions

3
doc/layering/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.aux
*.pdf
*.log

View File

@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="basic-layering.pdf">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3618"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective4058"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4089"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4120"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4151"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4365"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4386"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-6"
style="overflow:visible">
<path
id="path3618-4"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4449"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-5"
style="overflow:visible">
<path
id="path3618-1"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4668"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696-1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.633643"
inkscape:cx="191.36241"
inkscape:cy="685.97592"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1280"
inkscape:window-height="949"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2816"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
units="mm"
spacingx="5mm"
spacingy="5mm" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend);color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 88.582677,432.28344 159.448823,0"
id="path3592" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="255.20872"
y="435.23877"
id="text4042"><tspan
sodipodi:role="line"
id="tspan4044"
x="255.20872"
y="435.23877">time</tspan></text>
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818"
width="70.866142"
height="35.433071"
x="88.58268"
y="308.2677" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2"
width="70.86615"
height="35.433071"
x="124.01574"
y="343.70078" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2"
width="70.86615"
height="35.433071"
x="177.16534"
y="379.13385" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2-4"
width="35.433086"
height="35.433071"
x="265.74802"
y="379.13385" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="119.61775"
y="330.26825"
id="text4320"><tspan
sodipodi:role="line"
id="tspan4322"
x="119.61775"
y="330.26825">A</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="155.36281"
y="365.51532"
id="text4324"><tspan
sodipodi:role="line"
id="tspan4326"
x="155.36281"
y="365.51532">B</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="208.36243"
y="400.94839"
id="text4328"><tspan
sodipodi:role="line"
id="tspan4330"
x="208.36243"
y="400.94839">C</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="279.05457"
y="400.94839"
id="text4332"><tspan
sodipodi:role="line"
id="tspan4334"
x="279.05457"
y="400.94839">D</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 318.89764,432.28344 0,-124.01575"
id="path3592-8"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="307.30875"
y="301.75519"
id="text4406"><tspan
sodipodi:role="line"
id="tspan4408"
x="307.30875"
y="301.75519">layer</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,397.273 13.54507,0"
id="path4439" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="401.58279"
id="text4656"><tspan
sodipodi:role="line"
id="tspan4658"
x="328.09393"
y="401.58279">0</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 312.32197,361.87109 13.54507,0"
id="path4439-1" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.02194"
y="366.18088"
id="text4656-0-0"><tspan
sodipodi:role="line"
id="tspan4658-6-3"
x="328.02194"
y="366.18088">1</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,325.98423 13.54507,0"
id="path4439-1-6" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="329.49646"
id="text4742"><tspan
sodipodi:role="line"
id="tspan4744"
x="328.09393"
y="329.49646">2</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

9
doc/layering/build.sh Normal file
View File

@ -0,0 +1,9 @@
#!/bin/sh
for f in basic-layering explicit-layering1 explicit-layering2 tricky-explicit-layering; do
inkscape -z --export-area-drawing -f $f.svg --export-pdf $f.pdf
done
pdflatex layering.tex
pdflatex layering.tex

View File

@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="explicit-layering.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3618"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective4058"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4089"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4120"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4151"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4365"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4386"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-6"
style="overflow:visible">
<path
id="path3618-4"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4449"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-5"
style="overflow:visible">
<path
id="path3618-1"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4668"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696-1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.633643"
inkscape:cx="191.36241"
inkscape:cy="670.78783"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1280"
inkscape:window-height="949"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2816"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
units="mm"
spacingx="5mm"
spacingy="5mm" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend);color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 88.582677,432.28344 159.448823,0"
id="path3592" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="255.20872"
y="435.23877"
id="text4042"><tspan
sodipodi:role="line"
id="tspan4044"
x="255.20872"
y="435.23877">time</tspan></text>
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818"
width="106.29921"
height="35.433071"
x="88.582687"
y="308.2677" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2"
width="88.582687"
height="35.433071"
x="124.01574"
y="343.70078" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2"
width="70.86615"
height="35.433071"
x="177.16534"
y="379.13385" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2-4"
width="35.433086"
height="35.433071"
x="265.74802"
y="379.13385" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="137.33429"
y="330.26825"
id="text4320"><tspan
sodipodi:role="line"
id="tspan4322"
x="137.33429"
y="330.26825">A</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="164.22108"
y="365.51532"
id="text4324"><tspan
sodipodi:role="line"
id="tspan4326"
x="164.22108"
y="365.51532">B</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="208.36243"
y="400.94839"
id="text4328"><tspan
sodipodi:role="line"
id="tspan4330"
x="208.36243"
y="400.94839">C</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="279.05457"
y="400.94839"
id="text4332"><tspan
sodipodi:role="line"
id="tspan4334"
x="279.05457"
y="400.94839">D</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 318.89764,432.28344 0,-124.01575"
id="path3592-8"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="307.30875"
y="301.75519"
id="text4406"><tspan
sodipodi:role="line"
id="tspan4408"
x="307.30875"
y="301.75519">layer</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,397.273 13.54507,0"
id="path4439" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="401.58279"
id="text4656"><tspan
sodipodi:role="line"
id="tspan4658"
x="328.09393"
y="401.58279">0</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 312.32197,361.87109 13.54507,0"
id="path4439-1" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.02194"
y="366.18088"
id="text4656-0-0"><tspan
sodipodi:role="line"
id="tspan4658-6-3"
x="328.02194"
y="366.18088">1</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,325.98423 13.54507,0"
id="path4439-1-6" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="329.49646"
id="text4742"><tspan
sodipodi:role="line"
id="tspan4744"
x="328.09393"
y="329.49646">2</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="explicit-layering2.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3618"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective4058"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4089"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4120"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4151"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4365"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4386"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-6"
style="overflow:visible">
<path
id="path3618-4"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4449"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-5"
style="overflow:visible">
<path
id="path3618-1"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4668"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696-1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.633643"
inkscape:cx="191.36241"
inkscape:cy="670.02843"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1280"
inkscape:window-height="949"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2816"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
units="mm"
spacingx="5mm"
spacingy="5mm" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend);color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 88.582677,432.28344 159.448823,0"
id="path3592" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="255.20872"
y="435.23877"
id="text4042"><tspan
sodipodi:role="line"
id="tspan4044"
x="255.20872"
y="435.23877">time</tspan></text>
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818"
width="106.29921"
height="35.433071"
x="88.58268"
y="343.70078" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2"
width="88.582687"
height="35.433071"
x="124.01575"
y="379.13385" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2"
width="70.86615"
height="35.433071"
x="177.16534"
y="308.2677" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2-4"
width="35.433086"
height="35.433071"
x="265.74802"
y="379.13385" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="137.33429"
y="365.70132"
id="text4320"><tspan
sodipodi:role="line"
id="tspan4322"
x="137.33429"
y="365.70132">A</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="164.22108"
y="400.94839"
id="text4324"><tspan
sodipodi:role="line"
id="tspan4326"
x="164.22108"
y="400.94839">B</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="208.36243"
y="330.08224"
id="text4328"><tspan
sodipodi:role="line"
id="tspan4330"
x="208.36243"
y="330.08224">C</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="279.05457"
y="400.94839"
id="text4332"><tspan
sodipodi:role="line"
id="tspan4334"
x="279.05457"
y="400.94839">D</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 318.89764,432.28344 0,-124.01575"
id="path3592-8"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="307.30875"
y="301.75519"
id="text4406"><tspan
sodipodi:role="line"
id="tspan4408"
x="307.30875"
y="301.75519">layer</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,397.273 13.54507,0"
id="path4439" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="401.58279"
id="text4656"><tspan
sodipodi:role="line"
id="tspan4658"
x="328.09393"
y="401.58279">0</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 312.32197,361.87109 13.54507,0"
id="path4439-1" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.02194"
y="366.18088"
id="text4656-0-0"><tspan
sodipodi:role="line"
id="tspan4658-6-3"
x="328.02194"
y="366.18088">1</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,325.98423 13.54507,0"
id="path4439-1-6" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="329.49646"
id="text4742"><tspan
sodipodi:role="line"
id="tspan4744"
x="328.09393"
y="329.49646">2</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

150
doc/layering/layering.tex Normal file
View File

@ -0,0 +1,150 @@
\documentclass{article}
\title{Region Layering}
\author{}
\date{}
\usepackage{graphicx}
\begin{document}
\maketitle
\section{Introduction}
When regions overlap in time, we need to decide which one should be
played. Ardour has a few options to set how this decision is made.
\subsection{Layers}
Each region on a playlist is on a \emph{layer}. All overlapping regions
are on a unique layer, and when overlaps exist the highest-layered
region is played. This is illustrated in Figure~\ref{fig:basic-layering}.
\begin{figure}[ht]
\begin{center}
\includegraphics{basic-layering.pdf}
\end{center}
\caption{Basic region layering}
\label{fig:basic-layering}
\end{figure}
Here we see that region $A$ overlaps $B$, $B$ overlaps $C$, and
$D$ overlaps nothing. There are several ways in which these regions
could be arranged; in the drawing, $A$ is on layer~2, $B$ on layer~1,
$C$ and $D$ on layer~0. If this area is played back, region $A$ will
play in its entirety, followed by the end part of region $B$, followed
by the end part of region $C$, followed by the whole of region $D$.
This follows the basic rule that, at any given point, the region on
the highest layer will be played.
\section{Choice of layering}
There are two main decisions to be made with regards to how a playlist should be layered:
\begin{itemize}
\item Given overlapping regions, what order should they be layered in?
\item When should layering be changed?
\end{itemize}
\subsection{Layering order}
Ardour provides three-and-a-half ways to decide on the order in which
regions are layered. The most basic choice is:
\begin{itemize}
\item \emph{Later is higher} --- regions which are later in time will
be on higher layers.
\item \emph{Most recently added is higher} --- regions which were more
recently added to the playlist will be on higher layers.
\item \emph{Most recently edited or added is higher} --- regions which
were more recently edited or added to the playlist will be on
higher layers.
\end{itemize}
This choice can be set per-session from the \emph{Session Properties} dialogue
box.
\subsubsection{Explicit ordering}
There are also cases when none of these rules should apply. If, for
example, you want to put a given region at the top of the stack (on
the highest layer), this is possible using the region `raise to top'
command. Following such a command (called an `explicit layering'),
the regions on the playlist may no longer obey any of the standard
ordering rules.
This situation also arises when editing tracks using the `stacked' layer mode.
In this mode, almost all layering is explicit. When starting a region drag,
the other regions on a track spread apart vertically to allow the dragged
region to be dropped in any position within the region stack. The normal
layering rules will only be followed if a region is dropped on top of another;
in all other cases, explicit layering will be used to put the region wherever
it was dropped.
\subsection{When to update layering}
There are two distinct approaches to updating layering:
\begin{itemize}
\item Update whenever any region edit is performed.
\item Update only when a region is edited such that a new overlap has been set up.
\end{itemize}
The approach to use is optional, and can be set in \emph{Session Properties}.
This decision only has consequences when an explicit layering command has
been used. Consider the case in Figure~\ref{fig:explicit-layering1}.
\begin{figure}[ht]
\begin{center}
\includegraphics{explicit-layering1.pdf}
\end{center}
\caption{Explicit layering: stage 1}
\label{fig:explicit-layering1}
\end{figure}
Given that arrangement, imagine that we perform a `raise to top' on region $C$.
This results in the arrangement in Figure~\ref{fig:explicit-layering2}.
\begin{figure}[ht]
\begin{center}
\includegraphics{explicit-layering2.pdf}
\end{center}
\caption{Explicit layering: stage 2}
\label{fig:explicit-layering2}
\end{figure}
Imagine now that region $C$ is moved very slightly to the left, so
that it still overlaps both $A$ and $B$. If we are updating whenever
any region edit is performed, this will result in a relayer; the
regions' arrangement will go back to that in
Figure~\ref{fig:explicit-layering1}.
If, on the other hand, we only relayer when a new overlap is set up,
the region layering will remain as in
Figure~\ref{fig:explicit-layering2}. Before the edit, regions $A$,
$B$ and $C$ overlapped; after the edit, the situation is the same, so
no relayering is performed.
Another, more complex, example is shown in Figure~\ref{fig:tricky-explicit-layering}.
\begin{figure}[ht]
\begin{center}
\includegraphics{tricky-explicit-layering.pdf}
\end{center}
\caption{More complex explicit layering}
\label{fig:tricky-explicit-layering}
\end{figure}
% XXX: this makes no sense
Here, imagine that $C$ has been moved to the top of the stack with an explicit
`raise to top' command. Now consider an extension of $C$ so that its
right-hand edge overlaps $D$. If we are relayering only on new overlaps, this
case presents one new overlap (that of $C$ with $D$). In this case, $C$ is
moved according to the current layering rules so that it is correct with
respect to $D$. In addition, $A$ and $B$ are re-layered so that the relation
of $C$ to $A$ and $B$ is preserved.
\end{document}

View File

@ -0,0 +1,323 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="tricky-explicit-layering1.svg">
<defs
id="defs4">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3618"
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
</marker>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective4058"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4089"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4120"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4151"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4365"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4386"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-6"
style="overflow:visible">
<path
id="path3618-4"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4449"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend-5"
style="overflow:visible">
<path
id="path3618-1"
style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)" />
</marker>
<inkscape:perspective
id="perspective4668"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4696-1"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.633643"
inkscape:cx="191.36241"
inkscape:cy="670.78783"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1280"
inkscape:window-height="949"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
gridtolerance="10">
<inkscape:grid
type="xygrid"
id="grid2816"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
units="mm"
spacingx="5mm"
spacingy="5mm" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend);color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 88.582677,432.28344 159.448823,0"
id="path3592" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="255.20872"
y="435.23877"
id="text4042"><tspan
sodipodi:role="line"
id="tspan4044"
x="255.20872"
y="435.23877">time</tspan></text>
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818"
width="106.29921"
height="35.433071"
x="88.582695"
y="343.70078" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2"
width="88.582687"
height="35.433071"
x="124.01575"
y="379.13385" />
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2-4"
width="70.866142"
height="35.433071"
x="230.31496"
y="379.13385" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="137.33429"
y="365.70132"
id="text4320"><tspan
sodipodi:role="line"
id="tspan4322"
x="137.33429"
y="365.70132">A</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="164.22108"
y="400.94839"
id="text4324"><tspan
sodipodi:role="line"
id="tspan4326"
x="164.22108"
y="400.94839">B</tspan></text>
<rect
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2818-2-2"
width="44.545933"
height="35.433071"
x="177.16534"
y="308.2677" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="195.20232"
y="330.08224"
id="text4328"><tspan
sodipodi:role="line"
id="tspan4330"
x="195.20232"
y="330.08224">C</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="261.33801"
y="400.94839"
id="text4332"><tspan
sodipodi:role="line"
id="tspan4334"
x="261.33801"
y="400.94839">D</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 318.89764,432.28344 0,-124.01575"
id="path3592-8"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="307.30875"
y="301.75519"
id="text4406"><tspan
sodipodi:role="line"
id="tspan4408"
x="307.30875"
y="301.75519">layer</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.62500000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;color:#000000;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,397.273 13.54507,0"
id="path4439" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="401.58279"
id="text4656"><tspan
sodipodi:role="line"
id="tspan4658"
x="328.09393"
y="401.58279">0</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 312.32197,361.87109 13.54507,0"
id="path4439-1" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.02194"
y="366.18088"
id="text4656-0-0"><tspan
sodipodi:role="line"
id="tspan4658-6-3"
x="328.02194"
y="366.18088">1</tspan></text>
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.625;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 311.84462,325.98423 13.54507,0"
id="path4439-1-6" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
x="328.09393"
y="329.49646"
id="text4742"><tspan
sodipodi:role="line"
id="tspan4744"
x="328.09393"
y="329.49646">2</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -809,13 +809,14 @@ AudioStreamView::update_contents_height ()
void
AudioStreamView::update_content_height (CrossfadeView* cv)
{
if (_layer_display == Overlaid) {
switch (_layer_display) {
case Overlaid:
cv->set_y (0);
cv->set_height (height);
break;
} else {
case Stacked:
case Expanded:
layer_t const inl = cv->crossfade->in()->layer ();
layer_t const outl = cv->crossfade->out()->layer ();
@ -824,9 +825,13 @@ AudioStreamView::update_content_height (CrossfadeView* cv)
const double h = child_height ();
cv->set_y ((_layers - high - 1) * h);
cv->set_height ((high - low + 1) * h);
if (_layer_display == Stacked) {
cv->set_y ((_layers - high - 1) * h);
cv->set_height ((high - low + 1) * h);
} else {
cv->set_y (((_layers - high) * 2 - 1) * h);
cv->set_height (((high - low) * 2 + 1) * h);
}
}
}

View File

@ -87,15 +87,23 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session* sess, Canvas& c
void
AudioTimeAxisView::set_route (boost::shared_ptr<Route> rt)
{
_route = rt;
/* RouteTimeAxisView::set_route() sets up some things in the View,
so it must be created before RouteTimeAxis::set_route() is
called.
*/
_view = new AudioStreamView (*this);
RouteTimeAxisView::set_route (rt);
_view->apply_color (color (), StreamView::RegionColor);
// Make sure things are sane...
assert(!is_track() || is_audio_track());
subplugin_menu.set_name ("ArdourContextMenu");
_view = new AudioStreamView (*this);
ignore_toggle = false;
if (is_audio_track()) {

View File

@ -2477,12 +2477,12 @@ Editor::get_state ()
* TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
* in stacked region display mode, otherwise 0.
*/
std::pair<TimeAxisView *, layer_t>
std::pair<TimeAxisView *, double>
Editor::trackview_by_y_position (double y)
{
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
if (r.first) {
return r;
}

View File

@ -1032,7 +1032,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
/* track views */
TrackViewList track_views;
std::pair<TimeAxisView*, ARDOUR::layer_t> trackview_by_y_position (double);
std::pair<TimeAxisView*, double> trackview_by_y_position (double);
TimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const;
TrackViewList get_tracks_for_range_action () const;

View File

@ -485,9 +485,13 @@ RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
show_verbose_cursor_time (_last_frame_position);
pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
_last_pointer_time_axis_view = find_time_axis_view (tv.first);
_last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
if (tv.first->view()->layer_display() == Stacked) {
tv.first->view()->set_layer_display (Expanded);
}
}
double
@ -554,7 +558,7 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_r
}
bool
RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) const
RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
{
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
int const n = i->time_axis_view + delta_track;
@ -569,8 +573,13 @@ RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) cons
return false;
}
int const l = i->layer + delta_layer;
if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) {
double const l = i->layer + delta_layer;
/* Note that we allow layer to be up to 0.5 below zero, as this is used by `Expanded'
mode to allow the user to place a region below another on layer 0.
*/
if (delta_track == 0 && (l < -0.5 || l >= int (to->view()->layers()))) {
/* Off the top or bottom layer; note that we only refuse if the track hasn't changed.
If it has, the layers will be munged later anyway, so it's ok.
*/
@ -588,7 +597,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
assert (!_views.empty ());
/* Find the TimeAxisView that the pointer is now over */
pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
/* Bail early if we're not over a track */
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
@ -601,7 +610,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
/* Here's the current pointer position in terms of time axis view and layer */
int const current_pointer_time_axis_view = find_time_axis_view (tv.first);
layer_t const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
/* Work out the change in x */
framepos_t pending_region_position;
@ -609,7 +618,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
/* Work out the change in y */
int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
int delta_layer = current_pointer_layer - _last_pointer_layer;
double delta_layer = current_pointer_layer - _last_pointer_layer;
if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
/* this y movement is not allowed, so do no y movement this time */
@ -659,14 +668,24 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
confusion when dragging regions from non-zero layers onto different
tracks.
*/
int this_delta_layer = delta_layer;
double this_delta_layer = delta_layer;
if (delta_time_axis_view != 0) {
this_delta_layer = - i->layer;
}
/* The TimeAxisView that this region is now on */
TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
/* Ensure it is moved from stacked -> expanded if appropriate */
if (tv->view()->layer_display() == Stacked) {
tv->view()->set_layer_display (Expanded);
}
/* We're only allowed to go -ve in layer on Expanded views */
if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
this_delta_layer = - i->layer;
}
/* Set height */
rv->set_height (tv->view()->child_height ());
@ -695,10 +714,17 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
/* And adjust for the layer that it should be on */
StreamView* cv = tv->view ();
if (cv->layer_display() == Stacked) {
switch (cv->layer_display ()) {
case Overlaid:
break;
case Stacked:
y += (cv->layers() - i->layer - 1) * cv->child_height ();
break;
case Expanded:
y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
break;
}
/* Now move the region view */
rv->move (x_delta, y - rv->get_canvas_group()->property_y());
}
@ -789,8 +815,19 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
}
void
RegionMoveDrag::finished (GdkEvent *, bool movement_occurred)
RegionMotionDrag::finished (GdkEvent *, bool)
{
for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
if ((*i)->view()->layer_display() == Expanded) {
(*i)->view()->set_layer_display (Stacked);
}
}
}
void
RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
{
RegionMotionDrag::finished (ev, movement_occurred);
if (!movement_occurred) {
/* just a click */
return;
@ -924,6 +961,9 @@ RegionMoveDrag::finished_no_copy (
RegionSelection new_views;
PlaylistSet modified_playlists;
PlaylistSet frozen_playlists;
PlaylistSet relayer_suspended_playlists;
list<pair<boost::shared_ptr<Region>, double> > pending_relayers;
if (_brushing) {
/* all changes were made during motion event handlers */
@ -942,7 +982,7 @@ RegionMoveDrag::finished_no_copy (
RegionView* rv = i->view;
RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
layer_t const dest_layer = i->layer;
double const dest_layer = i->layer;
if (rv->region()->locked()) {
++i;
@ -1002,9 +1042,10 @@ RegionMoveDrag::finished_no_copy (
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
if (dest_rtv->view()->layer_display() == Stacked) {
rv->region()->set_layer (dest_layer);
rv->region()->set_pending_explicit_relayer (true);
bool const explicit_relayer = dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded;
if (explicit_relayer) {
pending_relayers.push_back (make_pair (rv->region (), dest_layer));
}
/* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
@ -1024,6 +1065,9 @@ RegionMoveDrag::finished_no_copy (
playlist->clear_changes ();
}
relayer_suspended_playlists.insert (playlist);
playlist->suspend_relayer ();
rv->region()->set_position (where);
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
@ -1068,10 +1112,18 @@ RegionMoveDrag::finished_no_copy (
_editor->selection->set (new_views);
}
for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
for (PlaylistSet::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
(*p)->thaw();
}
for (PlaylistSet::iterator p = relayer_suspended_playlists.begin(); p != relayer_suspended_playlists.end(); ++p) {
(*p)->resume_relayer ();
}
for (list<pair<boost::shared_ptr<Region>, double> >::iterator i = pending_relayers.begin(); i != pending_relayers.end(); ++i) {
i->first->playlist()->relayer (i->first, i->second);
}
/* write commands for the accumulated diffs for all our modified playlists */
add_stateful_diff_commands_for_playlists (modified_playlists);
@ -1137,9 +1189,8 @@ RegionMoveDrag::insert_region_into_playlist (
dest_playlist->add_region (region, where);
if (dest_rtv->view()->layer_display() == Stacked) {
region->set_layer (dest_layer);
region->set_pending_explicit_relayer (true);
if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
dest_playlist->relayer (region, dest_layer);
}
c.disconnect ();
@ -1188,6 +1239,12 @@ RegionMoveDrag::aborted (bool movement_occurred)
void
RegionMotionDrag::aborted (bool)
{
for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
if ((*i)->view()->layer_display() == Expanded) {
(*i)->view()->set_layer_display (Stacked);
}
}
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
TimeAxisView* tv = &(rv->get_time_axis_view ());
@ -1295,7 +1352,7 @@ RegionSpliceDrag::motion (GdkEvent* event, bool)
{
/* Which trackview is this ? */
pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
/* The region motion is only processed if the pointer is over

View File

@ -249,8 +249,11 @@ struct DraggingView
* or -1 if it is not visible.
*/
int time_axis_view;
/** layer that this region is currently being displayed on */
ARDOUR::layer_t layer;
/** Layer that this region is currently being displayed on. This is a double
rather than a layer_t as we use fractional layers during drags to allow the user
to indicate a new layer to put a region on.
*/
double layer;
double initial_y; ///< the initial y position of the view before any reparenting
framepos_t initial_position; ///< initial position of the region
framepos_t initial_end; ///< initial end position of the region
@ -295,7 +298,7 @@ public:
virtual void start_grab (GdkEvent *, Gdk::Cursor *);
virtual void motion (GdkEvent *, bool);
virtual void finished (GdkEvent *, bool) = 0;
virtual void finished (GdkEvent *, bool);
virtual void aborted (bool);
/** @return true if the regions being `moved' came from somewhere on the canvas;
@ -306,13 +309,13 @@ public:
protected:
double compute_x_delta (GdkEvent const *, ARDOUR::framecnt_t *);
bool y_movement_allowed (int, ARDOUR::layer_t) const;
bool y_movement_allowed (int, double) const;
bool _brushing;
ARDOUR::framepos_t _last_frame_position; ///< last position of the thing being dragged
double _total_x_delta;
int _last_pointer_time_axis_view;
ARDOUR::layer_t _last_pointer_layer;
double _last_pointer_layer;
};

View File

@ -35,7 +35,8 @@ namespace Gnome {
enum LayerDisplay {
Overlaid,
Stacked
Stacked,
Expanded
};
struct SelectionRect {

View File

@ -139,6 +139,8 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
*/
RouteTimeAxisView::set_route (rt);
_view->apply_color (_color, StreamView::RegionColor);
subplugin_menu.set_name ("ArdourContextMenu");
if (!gui_property ("note-range-min").empty ()) {

View File

@ -468,6 +468,7 @@ RouteTimeAxisView::build_display_menu ()
++overlaid;
break;
case Stacked:
case Expanded:
++stacked;
break;
}

View File

@ -272,9 +272,17 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
);
lm->add (LaterHigher, _("later is higher"));
lm->add (MoveAddHigher, _("most recently moved or added is higher"));
lm->add (AddOrBoundsChangeHigher, _("most recently edited or added is higher"));
lm->add (AddHigher, _("most recently added is higher"));
add_option (_("Misc"), new BoolOption (
"relayer-on-all-edits",
_("Relayer regions after every edit"),
sigc::mem_fun (*_session_config, &SessionConfiguration::get_relayer_on_all_edits),
sigc::mem_fun (*_session_config, &SessionConfiguration::set_relayer_on_all_edits)
));
add_option (_("Misc"), lm);
add_option (_("Misc"), new OptionEditorHeading (_("MIDI Options")));

View File

@ -57,7 +57,6 @@ StreamView::StreamView (RouteTimeAxisView& tv, ArdourCanvas::Group* background_g
, _samples_per_unit (_trackview.editor().get_current_zoom ())
, rec_updating(false)
, rec_active(false)
, region_color(_trackview.color())
, stream_base_color(0xFFFFFFFF)
, _layers (1)
, _layer_display (Overlaid)
@ -302,7 +301,7 @@ StreamView::playlist_layered (boost::weak_ptr<Track> wtr)
_layers = tr->playlist()->top_layer() + 1;
}
if (_layer_display == Stacked) {
if (_layer_display == Stacked || _layer_display == Expanded) {
update_contents_height ();
update_coverage_frames ();
} else {
@ -330,8 +329,6 @@ StreamView::playlist_switched (boost::weak_ptr<Track> wtr)
update_contents_height ();
update_coverage_frames ();
tr->playlist()->set_explicit_relayering (_layer_display == Stacked);
/* draw it */
redisplay_track ();
@ -569,10 +566,16 @@ StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results
double
StreamView::child_height () const
{
if (_layer_display == Stacked) {
switch (_layer_display) {
case Overlaid:
return height;
case Stacked:
return height / _layers;
case Expanded:
return height / (_layers * 2 + 1);
}
/* NOTREACHED */
return height;
}
@ -589,6 +592,9 @@ StreamView::update_contents_height ()
case Stacked:
(*i)->set_y (height - ((*i)->region()->layer() + 1) * h);
break;
case Expanded:
(*i)->set_y (height - ((*i)->region()->layer() + 1) * 2 * h);
break;
}
(*i)->set_height (h);
@ -600,6 +606,7 @@ StreamView::update_contents_height ()
i->rectangle->property_y2() = height;
break;
case Stacked:
case Expanded:
/* In stacked displays, the recregion is always at the top */
i->rectangle->property_y1() = 0;
i->rectangle->property_y2() = h;
@ -614,7 +621,6 @@ StreamView::set_layer_display (LayerDisplay d)
_layer_display = d;
update_contents_height ();
update_coverage_frames ();
_trackview.track()->playlist()->set_explicit_relayering (_layer_display == Stacked);
}
void

View File

@ -1195,10 +1195,10 @@ TimeAxisView::color_handler ()
* TimeAxisView is non-0 if this object covers y, or one of its children does.
* If the covering object is a child axis, then the child is returned.
* TimeAxisView is 0 otherwise.
* Layer index is the layer number if the TimeAxisView is valid and is in stacked
* region display mode, otherwise 0.
* Layer index is the layer number (possibly fractional) if the TimeAxisView is valid
* and is in stacked or expanded region display mode, otherwise 0.
*/
std::pair<TimeAxisView*, layer_t>
std::pair<TimeAxisView*, double>
TimeAxisView::covers_y_position (double y)
{
if (hidden()) {
@ -1208,15 +1208,30 @@ TimeAxisView::covers_y_position (double y)
if (_y_position <= y && y < (_y_position + height)) {
/* work out the layer index if appropriate */
layer_t l = 0;
if (layer_display () == Stacked && view ()) {
/* compute layer */
l = layer_t ((_y_position + height - y) / (view()->child_height ()));
/* clamp to max layers to be on the safe side; sometimes the above calculation
returns a too-high value */
if (l >= view()->layers ()) {
l = view()->layers() - 1;
double l = 0;
switch (layer_display ()) {
case Overlaid:
break;
case Stacked:
if (view ()) {
/* compute layer */
l = floor ((_y_position + height - y) / (view()->child_height ()));
/* clamp to max layers to be on the safe side; sometimes the above calculation
returns a too-high value */
if (l >= view()->layers ()) {
l = view()->layers() - 1;
}
}
break;
case Expanded:
if (view ()) {
int n = floor ((_y_position + height - y) / (view()->child_height ()));
l = n * 0.5 - 0.5;
if (l >= (view()->layers() - 0.5)) {
l = view()->layers() - 0.5;
}
}
break;
}
return std::make_pair (this, l);

View File

@ -146,7 +146,7 @@ class TimeAxisView : public virtual AxisView
virtual void reset_visual_state ();
std::pair<TimeAxisView*, ARDOUR::layer_t> covers_y_position (double);
std::pair<TimeAxisView*, double> covers_y_position (double);
virtual void step_height (bool);

View File

@ -63,8 +63,6 @@ namespace ARDOUR {
std::string translation_kill_path ();
bool translations_are_disabled ();
const layer_t max_layer = UCHAR_MAX;
static inline microseconds_t get_microseconds () {
return (microseconds_t) jack_get_time();
}

View File

@ -44,6 +44,9 @@
#include "ardour/session_object.h"
#include "ardour/data_type.h"
class PlaylistOverlapCacheTest;
class PlaylistLayeringTest;
namespace ARDOUR {
class Session;
@ -215,12 +218,6 @@ public:
void drop_regions ();
bool explicit_relayering () const {
return _explicit_relayering;
}
void set_explicit_relayering (bool e);
virtual boost::shared_ptr<Crossfade> find_crossfade (const PBD::ID &) const {
return boost::shared_ptr<Crossfade> ();
}
@ -228,6 +225,10 @@ public:
framepos_t find_next_top_layer_position (framepos_t) const;
uint32_t combine_ops() const { return _combine_ops; }
void relayer (boost::shared_ptr<Region>, double);
void suspend_relayer ();
void resume_relayer ();
protected:
friend class Session;
@ -288,17 +289,10 @@ public:
bool _frozen;
uint32_t subcnt;
PBD::ID _orig_track_id;
uint64_t layer_op_counter;
framecnt_t freeze_length;
bool auto_partition;
uint32_t _combine_ops;
/** true if relayering should be done using region's current layers and their `pending explicit relayer'
* flags; otherwise false if relayering should be done using the layer-model (most recently moved etc.)
* Explicit relayering is used by tracks in stacked regionview mode.
*/
bool _explicit_relayering;
void init (bool hide);
bool holding_state () const {
@ -361,16 +355,14 @@ public:
boost::shared_ptr<Playlist> cut (framepos_t start, framecnt_t cnt, bool result_is_hidden);
boost::shared_ptr<Playlist> copy (framepos_t start, framecnt_t cnt, bool result_is_hidden);
int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
void relayer ();
void relayer (boost::shared_ptr<Region>);
void relayer (RegionList const &);
void begin_undo ();
void end_undo ();
void unset_freeze_parent (Playlist*);
void unset_freeze_child (Playlist*);
void timestamp_layer_op (boost::shared_ptr<Region>);
void _split_region (boost::shared_ptr<Region>, framepos_t position);
typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions;
@ -391,6 +383,71 @@ public:
with its constituent regions
*/
virtual void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>) {}
private:
friend class ::PlaylistOverlapCacheTest;
friend class ::PlaylistLayeringTest;
/** A class which is used to store temporary (fractional)
* layer assignments for some regions.
*/
class TemporaryLayers
{
public:
void set (boost::shared_ptr<Region>, double);
double get (boost::shared_ptr<Region>) const;
private:
typedef std::map<boost::shared_ptr<Region>, double> Map;
Map _map;
};
/** Class to sort by temporary layer, for use with std::list<>::sort() */
class SortByTemporaryLayer
{
public:
SortByTemporaryLayer (TemporaryLayers const & t)
: _temporary_layers (t) {}
bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) const {
return _temporary_layers.get (a) < _temporary_layers.get (b);
}
private:
Playlist::TemporaryLayers const & _temporary_layers;
};
/** A cache of what overlaps what, for a given playlist in a given state.
* Divides a playlist up into time periods and notes which regions cover those
* periods, so that get() is reasonably quick.
*/
class OverlapCache
{
public:
OverlapCache (Playlist *);
RegionList get (Evoral::Range<framepos_t>) const;
private:
std::pair<int, int> cache_indices (Evoral::Range<framepos_t>) const;
double _division_size;
std::vector<RegionList> _cache;
Evoral::Range<framepos_t> _range;
static int const _divisions;
};
TemporaryLayers compute_temporary_layers (RegionList const &);
void commit_temporary_layers (TemporaryLayers const &);
RegionList recursive_regions_touched (boost::shared_ptr<Region>, OverlapCache const &, boost::shared_ptr<Region>) const;
void recursive_regions_touched_sub (boost::shared_ptr<Region>, OverlapCache const &, boost::shared_ptr<Region>, RegionList &) const;
void timestamp_layer_op (LayerOp, boost::shared_ptr<Region>);
uint64_t layer_op_counter;
bool _relayer_suspended;
};
} /* namespace ARDOUR */

View File

@ -112,6 +112,7 @@ class Region
framepos_t start () const { return _start; }
framecnt_t length () const { return _length; }
layer_t layer () const { return _layer; }
Evoral::Range<framepos_t> bounds () const;
framecnt_t source_length(uint32_t n) const;
uint32_t max_source_level () const;
@ -201,7 +202,7 @@ class Region
void cut_front (framepos_t new_position);
void cut_end (framepos_t new_position);
void set_layer (layer_t l); /* ONLY Playlist can call this */
void set_layer (layer_t l); /* ONLY Playlist should call this */
void raise ();
void lower ();
void raise_to_top ();
@ -251,8 +252,8 @@ class Region
virtual boost::shared_ptr<Region> get_parent() const;
uint64_t last_layer_op() const { return _last_layer_op; }
void set_last_layer_op (uint64_t when);
uint64_t last_layer_op (LayerOp) const;
void set_last_layer_op (LayerOp, uint64_t);
virtual bool is_dependent() const { return false; }
virtual bool depends_on (boost::shared_ptr<Region> /*other*/) const { return false; }
@ -293,16 +294,13 @@ class Region
void invalidate_transients ();
void set_pending_explicit_relayer (bool p) {
_pending_explicit_relayer = p;
}
bool pending_explicit_relayer () const {
return _pending_explicit_relayer;
}
void drop_sources ();
/** @return our bounds the last time our relayer() method was called */
Evoral::Range<framepos_t> last_relayer_bounds () const {
return Evoral::Range<framepos_t> (_last_relayer_bounds_from, _last_relayer_bounds_to);
}
protected:
friend class RegionFactory;
@ -387,16 +385,17 @@ class Region
PBD::Property<float> _shift;
PBD::EnumProperty<PositionLockStyle> _position_lock_style;
/* XXX: could use a Evoral::Range<> but I'm too lazy to make PBD::Property serialize such a thing nicely */
PBD::Property<framepos_t> _last_relayer_bounds_from; ///< from of our bounds last time relayer() was called
PBD::Property<framepos_t> _last_relayer_bounds_to; ///< to of our bounds last time relayer() was called
PBD::Property<uint64_t> _last_layer_op_add;
PBD::Property<uint64_t> _last_layer_op_bounds_change;
framecnt_t _last_length;
framepos_t _last_position;
mutable RegionEditState _first_edit;
Timecode::BBT_Time _bbt_time;
uint64_t _last_layer_op; ///< timestamp
/** true if this region has had its layer explicitly set since the playlist last relayered */
bool _pending_explicit_relayer;
void register_properties ();
void use_sources (SourceList const &);

View File

@ -30,31 +30,24 @@ struct RegionSortByPosition {
}
};
struct RegionSortByLastLayerOp {
bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
return a->last_layer_op() < b->last_layer_op();
}
};
struct RegionSortByLayer {
bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
return a->layer() < b->layer();
}
};
struct RegionSortByLayerWithPending {
bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
double p = a->layer ();
if (a->pending_explicit_relayer()) {
p += 0.5;
}
double q = b->layer ();
if (b->pending_explicit_relayer()) {
q += 0.5;
}
struct RegionSortByAdd {
bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
return (
(a->last_layer_op (LayerOpAdd) < b->last_layer_op (LayerOpAdd))
);
}
};
struct RegionSortByAddOrBounds {
bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
uint64_t const p = std::max (a->last_layer_op (LayerOpAdd), a->last_layer_op (LayerOpBoundsChange));
uint64_t const q = std::max (b->last_layer_op (LayerOpAdd), b->last_layer_op (LayerOpBoundsChange));
return p < q;
}
};

View File

@ -47,7 +47,8 @@ CONFIG_VARIABLE_SPECIAL(std::string, audio_search_path, "audio-search-path", "",
CONFIG_VARIABLE_SPECIAL(std::string, midi_search_path, "midi-search-path", "", search_path_expand)
CONFIG_VARIABLE (std::string, bwf_country_code, "bwf-country-code", "US")
CONFIG_VARIABLE (std::string, bwf_organization_code, "bwf-organization-code", "US")
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", MoveAddHigher)
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", AddOrBoundsChangeHigher)
CONFIG_VARIABLE (bool, relayer_on_all_edits, "relayer-on-all-edits", true)
CONFIG_VARIABLE (std::string, auditioner_output_left, "auditioner-output-left", "default")
CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right", "default")
CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", true)

View File

@ -75,6 +75,7 @@ namespace ARDOUR {
static const framepos_t max_framepos = INT64_MAX;
static const framecnt_t max_framecnt = INT64_MAX;
static const layer_t max_layer = UINT32_MAX;
// a set of (time) intervals: first of pair is the offset of the start within the region, second is the offset of the end
typedef std::list<std::pair<frameoffset_t, frameoffset_t> > AudioIntervalResult;
@ -410,7 +411,7 @@ namespace ARDOUR {
enum LayerModel {
LaterHigher,
MoveAddHigher,
AddOrBoundsChangeHigher,
AddHigher
};
@ -591,6 +592,11 @@ namespace ARDOUR {
FadeLogB
};
enum LayerOp {
LayerOpAdd,
LayerOpBoundsChange
};
} // namespace ARDOUR

View File

@ -1510,15 +1510,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
}
i_am_the_modifier++;
if (_playlist->explicit_relayering()) {
/* We are in `explicit relayering' mode, so we must specify which layer this new region
should end up on. Put it at the top.
*/
region->set_layer (_playlist->top_layer() + 1);
region->set_pending_explicit_relayer (true);
}
_playlist->add_region (region, (*ci)->start, 1, non_layered());
i_am_the_modifier--;

View File

@ -265,7 +265,7 @@ setup_enum_writer ()
REGISTER (_CrossfadeModel);
REGISTER_ENUM (LaterHigher);
REGISTER_ENUM (MoveAddHigher);
REGISTER_ENUM (AddOrBoundsChangeHigher);
REGISTER_ENUM (AddHigher);
REGISTER (_LayerModel);

File diff suppressed because it is too large Load Diff

View File

@ -73,6 +73,10 @@ namespace ARDOUR {
PBD::PropertyDescriptor<float> stretch;
PBD::PropertyDescriptor<float> shift;
PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
PBD::PropertyDescriptor<framepos_t> last_relayer_bounds_from;
PBD::PropertyDescriptor<framepos_t> last_relayer_bounds_to;
PBD::PropertyDescriptor<uint64_t> last_layer_op_add;
PBD::PropertyDescriptor<uint64_t> last_layer_op_bounds_change;
}
}
@ -127,6 +131,14 @@ Region::make_property_quarks ()
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n", Properties::shift.property_id));
Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n", Properties::position_lock_style.property_id));
Properties::last_relayer_bounds_from.property_id = g_quark_from_static_string (X_("last-relayer-bounds-from"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_from = %1\n", Properties::last_relayer_bounds_from.property_id));
Properties::last_relayer_bounds_to.property_id = g_quark_from_static_string (X_("last-relayer-bounds-to"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_relayer_bounds_to = %1\n", Properties::last_relayer_bounds_to.property_id));
Properties::last_layer_op_add.property_id = g_quark_from_static_string (X_("last-layer-op-add"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_add = %1\n", Properties::last_layer_op_add.property_id));
Properties::last_layer_op_bounds_change.property_id = g_quark_from_static_string (X_("last-layer-op-bounds-change"));
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for last_layer_op_bounds_change = %1\n", Properties::last_layer_op_bounds_change.property_id));
}
void
@ -157,6 +169,10 @@ Region::register_properties ()
add_property (_stretch);
add_property (_shift);
add_property (_position_lock_style);
add_property (_last_relayer_bounds_from);
add_property (_last_relayer_bounds_to);
add_property (_last_layer_op_add);
add_property (_last_layer_op_bounds_change);
}
#define REGION_DEFAULT_STATE(s,l) \
@ -182,7 +198,11 @@ Region::register_properties ()
, _ancestral_length (Properties::ancestral_length, (l)) \
, _stretch (Properties::stretch, 1.0) \
, _shift (Properties::shift, 1.0) \
, _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime)
, _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime) \
, _last_relayer_bounds_from (Properties::last_relayer_bounds_from, 0) \
, _last_relayer_bounds_to (Properties::last_relayer_bounds_to, 0) \
, _last_layer_op_add (Properties::last_layer_op_add, 0) \
, _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, 0)
#define REGION_COPY_STATE(other) \
_sync_marked (Properties::sync_marked, other->_sync_marked) \
@ -207,7 +227,11 @@ Region::register_properties ()
, _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
, _stretch (Properties::stretch, other->_stretch) \
, _shift (Properties::shift, other->_shift) \
, _position_lock_style (Properties::position_lock_style, other->_position_lock_style)
, _position_lock_style (Properties::position_lock_style, other->_position_lock_style) \
, _last_relayer_bounds_from (Properties::last_relayer_bounds_from, other->_last_relayer_bounds_from) \
, _last_relayer_bounds_to (Properties::last_relayer_bounds_to, other->_last_relayer_bounds_to) \
, _last_layer_op_add (Properties::last_layer_op_add, other->_last_layer_op_add) \
, _last_layer_op_bounds_change (Properties::last_layer_op_bounds_change, other->_last_layer_op_bounds_change)
/* derived-from-derived constructor (no sources in constructor) */
Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
@ -217,11 +241,8 @@ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& n
, _last_length (length)
, _last_position (0)
, _first_edit (EditChangesNothing)
, _last_layer_op(0)
, _pending_explicit_relayer (false)
{
register_properties ();
/* no sources at this point */
}
@ -233,8 +254,6 @@ Region::Region (const SourceList& srcs)
, _last_length (0)
, _last_position (0)
, _first_edit (EditChangesNothing)
, _last_layer_op (0)
, _pending_explicit_relayer (false)
{
register_properties ();
@ -254,9 +273,6 @@ Region::Region (boost::shared_ptr<const Region> other)
, _last_length (other->_last_length)
, _last_position(other->_last_position) \
, _first_edit (EditChangesNothing)
, _last_layer_op (0)
, _pending_explicit_relayer (false)
{
register_properties ();
@ -326,9 +342,6 @@ Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset)
, _last_length (other->_last_length)
, _last_position(other->_last_position) \
, _first_edit (EditChangesNothing)
, _last_layer_op (0)
, _pending_explicit_relayer (false)
{
register_properties ();
@ -383,8 +396,6 @@ Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
, _last_length (other->_last_length)
, _last_position (other->_last_position)
, _first_edit (EditChangesID)
, _last_layer_op (other->_last_layer_op)
, _pending_explicit_relayer (false)
{
register_properties ();
@ -1123,9 +1134,12 @@ Region::set_layer (layer_t l)
{
if (_layer != l) {
_layer = l;
send_change (Properties::layer);
}
Evoral::Range<framepos_t> const b = bounds ();
_last_relayer_bounds_from = b.from;
_last_relayer_bounds_to = b.to;
}
XMLNode&
@ -1317,9 +1331,16 @@ Region::send_change (const PropertyChange& what_changed)
}
void
Region::set_last_layer_op (uint64_t when)
Region::set_last_layer_op (LayerOp op, uint64_t when)
{
_last_layer_op = when;
switch (op) {
case LayerOpAdd:
_last_layer_op_add = when;
break;
case LayerOpBoundsChange:
_last_layer_op_bounds_change = when;
break;
}
}
bool
@ -1661,3 +1682,25 @@ Region::post_set (const PropertyChange& pc)
recompute_position_from_lock_style ();
}
}
uint64_t
Region::last_layer_op (LayerOp op) const
{
switch (op) {
case LayerOpAdd:
return _last_layer_op_add;
case LayerOpBoundsChange:
return _last_layer_op_bounds_change;
}
/* NOTREACHED */
return 0;
}
Evoral::Range<framepos_t>
Region::bounds () const
{
return Evoral::Range<framepos_t> (_position, _position + _length);
}

View File

@ -19,6 +19,8 @@ export ARDOUR_PANNER_PATH=$libs/panners/2in2out:$libs/panners/1in2out:$libs/pann
if [ "$1" == "--debug" ]; then
gdb ./libs/ardour/run-tests
elif [ "$1" == "--valgrind" ]; then
valgrind --tool="memcheck" ./libs/ardour/run-tests
else
./libs/ardour/run-tests
fi

View File

@ -974,7 +974,27 @@ int
Session::load_options (const XMLNode& node)
{
LocaleGuard lg (X_("POSIX"));
config.set_variables (node);
/* Copy the node */
XMLNode node_copy = node;
/* XXX: evil hack: fix up sessions from before the layering alterations
(during A3 beta)
*/
XMLNodeList children = node_copy.children ();
for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
XMLProperty* p = (*i)->property (X_("name"));
if (p && p->name() == X_("name") && p->value() == X_("layer-model") ) {
p = (*i)->property (X_("value"));
if (p && p->value() == X_("MoveAddHigher")) {
(*i)->add_property (X_("value"), X_("AddOrBoundsChangeHigher"));
}
}
}
config.set_variables (node_copy);
return 0;
}

View File

@ -1,13 +1,14 @@
#include "midi++/manager.h"
#include "pbd/textreceiver.h"
#include "pbd/compose.h"
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "midi++/manager.h"
#include "ardour/playlist_factory.h"
#include "ardour/source_factory.h"
#include "ardour/region.h"
#include "ardour/region_factory.h"
#include "ardour/session.h"
#include "ardour/audiosource.h"
#include "ardour/audioengine.h"
#include "playlist_layering_test.h"
#include "test_receiver.h"
CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistLayeringTest);
@ -15,68 +16,28 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
class TestReceiver : public Receiver
{
protected:
void receive (Transmitter::Channel chn, const char * str) {
const char *prefix = "";
switch (chn) {
case Transmitter::Error:
prefix = ": [ERROR]: ";
break;
case Transmitter::Info:
/* ignore */
return;
case Transmitter::Warning:
prefix = ": [WARNING]: ";
break;
case Transmitter::Fatal:
prefix = ": [FATAL]: ";
break;
case Transmitter::Throw:
/* this isn't supposed to happen */
abort ();
}
/* note: iostreams are already thread-safe: no external
lock required.
*/
cout << prefix << str << endl;
if (chn == Transmitter::Fatal) {
exit (9);
}
}
};
TestReceiver test_receiver;
int const PlaylistLayeringTest::num_regions = 6;
void
PlaylistLayeringTest::setUp ()
{
string const test_session_path = "libs/ardour/test/playlist_layering_test";
string const test_wav_path = "libs/ardour/test/playlist_layering_test/playlist_layering_test.wav";
system (string_compose ("rm -rf %1", test_session_path).c_str());
TestNeedingSession::setUp ();
string const test_wav_path = "libs/ardour/test/test.wav";
init (false, true);
SessionEvent::create_per_thread_pool ("test", 512);
test_receiver.listen_to (error);
test_receiver.listen_to (info);
test_receiver.listen_to (fatal);
test_receiver.listen_to (warning);
AudioEngine* engine = new AudioEngine ("test", "");
MIDI::Manager::create (engine->jack ());
CPPUNIT_ASSERT (engine->start () == 0);
_session = new Session (*engine, test_session_path, "playlist_layering_test");
engine->set_session (_session);
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100);
system ("pwd");
/* Must write some data to our source, otherwise regions which use it will
be limited in whether they can be trimmed or not.
*/
boost::shared_ptr<AudioSource> a = boost::dynamic_pointer_cast<AudioSource> (_source);
Sample silence[512];
memset (silence, 0, 512 * sizeof (Sample));
a->write (silence, 512);
_region = new boost::shared_ptr<Region>[num_regions];
}
void
@ -84,68 +45,303 @@ PlaylistLayeringTest::tearDown ()
{
_playlist.reset ();
_source.reset ();
for (int i = 0; i < 16; ++i) {
for (int i = 0; i < num_regions; ++i) {
_region[i].reset ();
}
AudioEngine::instance()->remove_session ();
delete _session;
EnumWriter::destroy ();
MIDI::Manager::destroy ();
AudioEngine::destroy ();
delete[] _region;
TestNeedingSession::tearDown ();
}
void
PlaylistLayeringTest::create_three_short_regions ()
PlaylistLayeringTest::create_short_regions ()
{
PropertyList plist;
plist.add (Properties::start, 0);
plist.add (Properties::length, 100);
for (int i = 0; i < 3; ++i) {
for (int i = 0; i < num_regions; ++i) {
_region[i] = RegionFactory::create (_source, plist);
_region[i]->set_name (string_compose ("%1", char (int ('A') + i)));
}
}
void
PlaylistLayeringTest::addHigherTest ()
PlaylistLayeringTest::laterHigher_relayerOnAll_Test ()
{
_session->config.set_layer_model (AddHigher);
create_three_short_regions ();
_session->config.set_layer_model (LaterHigher);
_session->config.set_relayer_on_all_edits (true);
create_short_regions ();
_playlist->add_region (_region[0], 0);
_playlist->add_region (_region[1], 10);
_playlist->add_region (_region[2], 20);
/* three overlapping regions */
_playlist->add_region (_region[A], 0);
_playlist->add_region (_region[B], 10);
_playlist->add_region (_region[C], 20);
/* and another non-overlapping one */
_playlist->add_region (_region[D], 200);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ());
/* LaterHigher means that they should be arranged thus */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
_region[0]->set_position (5);
_region[A]->set_position (5);
/* region move should have no effect */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ());
/* Region move should have no effect in LaterHigher mode */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> bottom should give C A B, not touching D */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> top should go back to A B C, not touching D */
_region[C]->raise_to_top ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
}
void
PlaylistLayeringTest::moveAddHigherTest ()
PlaylistLayeringTest::addHigher_relayerOnAll_Test ()
{
_session->config.set_layer_model (MoveAddHigher);
create_three_short_regions ();
_session->config.set_layer_model (AddHigher);
_session->config.set_relayer_on_all_edits (true);
create_short_regions ();
_playlist->add_region (_region[0], 0);
_playlist->add_region (_region[1], 10);
_playlist->add_region (_region[2], 20);
/* three overlapping regions */
_playlist->add_region (_region[A], 0);
_playlist->add_region (_region[B], 10);
_playlist->add_region (_region[C], 20);
/* and another non-overlapping one */
_playlist->add_region (_region[D], 200);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ());
/* AddHigher means that they should be arranged thus */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
_region[0]->set_position (5);
_region[A]->set_position (5);
/* region move should have put 0 on top */
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[0]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[1]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[2]->layer ());
/* region move should have no effect in AddHigher mode */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> bottom should give C A B, not touching D */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> top should go back to A B C, not touching D */
_region[C]->raise_to_top ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
}
void
PlaylistLayeringTest::addOrBoundsHigher_relayerOnAll_Test ()
{
_session->config.set_layer_model (AddOrBoundsChangeHigher);
_session->config.set_relayer_on_all_edits (true);
create_short_regions ();
/* three overlapping regions */
_playlist->add_region (_region[A], 0);
_playlist->add_region (_region[B], 10);
_playlist->add_region (_region[C], 20);
/* and another non-overlapping one */
_playlist->add_region (_region[D], 200);
/* AddOrBoundsHigher means that they should be arranged thus */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* region move should put A on top for B C A, not touching D */
_region[A]->set_position (5);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> bottom should give C B A, not touching D */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> top should go back to B A C, not touching D */
_region[C]->raise_to_top ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Put C on the bottom */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Now move it slightly, and it should go back to the top again */
_region[C]->set_position (21);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Put C back on the bottom */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Trim it slightly, and it should go back to the top again */
_region[C]->trim_front (23);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Same with the end */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
_region[C]->trim_end (118);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
}
void
PlaylistLayeringTest::addOrBoundsHigher_relayerWhenNecessary_Test ()
{
_session->config.set_layer_model (AddOrBoundsChangeHigher);
_session->config.set_relayer_on_all_edits (false);
create_short_regions ();
/* three overlapping regions */
_playlist->add_region (_region[A], 0);
_playlist->add_region (_region[B], 10);
_playlist->add_region (_region[C], 20);
/* and another non-overlapping one */
_playlist->add_region (_region[D], 200);
/* AddOrBoundsHigher means that they should be arranged thus */
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
_region[A]->set_position (5);
/* region move should not have changed anything, since in
this mode we only relayer when there is a new overlap
*/
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> bottom should give C A B, not touching D */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* C -> top should go back to A B C, not touching D */
_region[C]->raise_to_top ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Put C on the bottom */
_region[C]->lower_to_bottom ();
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
/* Now move it slightly, and it should stay where it is */
_region[C]->set_position (21);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
}
void
PlaylistLayeringTest::lastLayerOpTest ()
{
create_short_regions ();
_playlist->add_region (_region[A], 0);
CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpAdd));
uint64_t const last_add = _region[A]->last_layer_op (LayerOpAdd);
_region[A]->set_position (42);
CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
_region[A]->trim_front (46);
CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
_region[A]->trim_end (102);
CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
}
void
PlaylistLayeringTest::recursiveRelayerTest ()
{
_session->config.set_layer_model (AddOrBoundsChangeHigher);
_session->config.set_relayer_on_all_edits (false);
create_short_regions ();
_playlist->add_region (_region[A], 100);
_playlist->add_region (_region[B], 125);
_playlist->add_region (_region[C], 50);
_playlist->add_region (_region[D], 250);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
_region[A]->set_position (200);
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
CPPUNIT_ASSERT_EQUAL (layer_t (3), _region[C]->layer ());
}

View File

@ -1,5 +1,6 @@
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include "test_needing_session.h"
namespace ARDOUR {
class Session;
@ -7,25 +8,42 @@ namespace ARDOUR {
class Source;
}
class PlaylistLayeringTest : public CppUnit::TestFixture
class PlaylistLayeringTest : public TestNeedingSession
{
CPPUNIT_TEST_SUITE (PlaylistLayeringTest);
CPPUNIT_TEST (addHigherTest);
CPPUNIT_TEST (moveAddHigherTest);
CPPUNIT_TEST (lastLayerOpTest);
CPPUNIT_TEST (addHigher_relayerOnAll_Test);
CPPUNIT_TEST (addOrBoundsHigher_relayerOnAll_Test);
CPPUNIT_TEST (laterHigher_relayerOnAll_Test);
CPPUNIT_TEST (addOrBoundsHigher_relayerWhenNecessary_Test);
CPPUNIT_TEST (recursiveRelayerTest);
CPPUNIT_TEST_SUITE_END ();
public:
void setUp ();
void tearDown ();
void addHigherTest ();
void moveAddHigherTest ();
void lastLayerOpTest ();
void addHigher_relayerOnAll_Test ();
void addOrBoundsHigher_relayerOnAll_Test ();
void laterHigher_relayerOnAll_Test ();
void addOrBoundsHigher_relayerWhenNecessary_Test ();
void recursiveRelayerTest ();
private:
void create_three_short_regions ();
void create_short_regions ();
static int const num_regions;
enum {
A = 0,
B,
C,
D,
E,
F
};
ARDOUR::Session* _session;
boost::shared_ptr<ARDOUR::Playlist> _playlist;
boost::shared_ptr<ARDOUR::Source> _source;
boost::shared_ptr<ARDOUR::Region> _region[16];
boost::shared_ptr<ARDOUR::Region>* _region;
};

View File

@ -0,0 +1,119 @@
#include "pbd/compose.h"
#include "ardour/playlist.h"
#include "ardour/playlist_factory.h"
#include "ardour/source_factory.h"
#include "ardour/region.h"
#include "ardour/region_sorters.h"
#include "ardour/region_factory.h"
#include "playlist_overlap_cache_test.h"
using namespace std;
using namespace PBD;
using namespace ARDOUR;
CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistOverlapCacheTest);
void
PlaylistOverlapCacheTest::tearDown ()
{
_playlist.reset ();
_source.reset ();
TestNeedingSession::tearDown ();
}
void
PlaylistOverlapCacheTest::basicTest ()
{
string const test_wav_path = "libs/ardour/test/test.wav";
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100);
PropertyList plist;
plist.add (Properties::length, 256);
boost::shared_ptr<Region> regionA = RegionFactory::create (_source, plist);
regionA->set_name ("A");
_playlist->add_region (regionA, 0);
{
Playlist::OverlapCache cache (_playlist.get ());
Playlist::RegionList rl = cache.get (Evoral::Range<framepos_t> (0, 256));
CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ());
CPPUNIT_ASSERT_EQUAL (regionA, rl.front ());
rl = cache.get (Evoral::Range<framepos_t> (-1000, 1000));
CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ());
CPPUNIT_ASSERT_EQUAL (regionA, rl.front ());
}
boost::shared_ptr<Region> regionB = RegionFactory::create (_source, plist);
regionA->set_name ("B");
_playlist->add_region (regionB, 53);
{
Playlist::OverlapCache cache (_playlist.get ());
Playlist::RegionList rl = cache.get (Evoral::Range<framepos_t> (0, 256));
CPPUNIT_ASSERT_EQUAL (size_t (2), rl.size ());
rl.sort (RegionSortByPosition ());
CPPUNIT_ASSERT_EQUAL (regionA, rl.front ());
CPPUNIT_ASSERT_EQUAL (regionB, rl.back ());
rl = cache.get (Evoral::Range<framepos_t> (260, 274));
CPPUNIT_ASSERT_EQUAL (size_t (1), rl.size ());
CPPUNIT_ASSERT_EQUAL (regionB, rl.front ());
}
}
void
PlaylistOverlapCacheTest::stressTest ()
{
string const test_wav_path = "libs/ardour/test/test.wav";
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100);
srand (42);
int const num_regions = rand () % 256;
for (int i = 0; i < num_regions; ++i) {
PropertyList plist;
plist.add (Properties::length, rand () % 32768);
boost::shared_ptr<Region> r = RegionFactory::create (_source, plist);
r->set_name (string_compose ("%1", i));
_playlist->add_region (r, rand() % 32768);
}
Playlist::OverlapCache cache (_playlist.get ());
int const tests = rand () % 256;
for (int i = 0; i < tests; ++i) {
framepos_t const start = rand () % 32768;
framepos_t const length = rand () % 32768;
framepos_t const end = start + length;
Playlist::RegionList cached = cache.get (Evoral::Range<framepos_t> (start, end));
Playlist::RegionList actual;
Playlist::RegionList regions = _playlist->region_list().rlist();
for (Playlist::RegionList::iterator j = regions.begin(); j != regions.end(); ++j) {
if ((*j)->coverage (start, end) != OverlapNone) {
actual.push_back (*j);
}
}
cached.sort (RegionSortByPosition ());
actual.sort (RegionSortByPosition ());
CPPUNIT_ASSERT_EQUAL (actual.size (), cached.size ());
Playlist::RegionList::iterator j = actual.begin ();
Playlist::RegionList::iterator k = cached.begin ();
for (; j != actual.end(); ++j, ++k) {
CPPUNIT_ASSERT_EQUAL (*j, *k);
}
}
}

View File

@ -0,0 +1,20 @@
#include "test_needing_session.h"
class PlaylistOverlapCacheTest : public TestNeedingSession
{
public:
CPPUNIT_TEST_SUITE (PlaylistOverlapCacheTest);
CPPUNIT_TEST (basicTest);
CPPUNIT_TEST (stressTest);
CPPUNIT_TEST_SUITE_END ();
public:
void tearDown ();
void basicTest ();
void stressTest ();
private:
boost::shared_ptr<ARDOUR::Playlist> _playlist;
boost::shared_ptr<ARDOUR::Source> _source;
};

View File

@ -0,0 +1,48 @@
#include "midi++/manager.h"
#include "pbd/textreceiver.h"
#include "pbd/compose.h"
#include "pbd/enumwriter.h"
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "test_needing_session.h"
#include "test_receiver.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
TestReceiver test_receiver;
void
TestNeedingSession::setUp ()
{
string const test_session_path = "libs/ardour/test/test_session";
system (string_compose ("rm -rf %1", test_session_path).c_str());
init (false, true);
SessionEvent::create_per_thread_pool ("test", 512);
test_receiver.listen_to (error);
test_receiver.listen_to (info);
test_receiver.listen_to (fatal);
test_receiver.listen_to (warning);
AudioEngine* engine = new AudioEngine ("test", "");
MIDI::Manager::create (engine->jack ());
CPPUNIT_ASSERT (engine->start () == 0);
_session = new Session (*engine, test_session_path, "test_session");
engine->set_session (_session);
}
void
TestNeedingSession::tearDown ()
{
AudioEngine::instance()->remove_session ();
delete _session;
EnumWriter::destroy ();
MIDI::Manager::destroy ();
AudioEngine::destroy ();
}

View File

@ -0,0 +1,16 @@
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
namespace ARDOUR {
class Session;
}
class TestNeedingSession : public CppUnit::TestFixture
{
public:
void setUp ();
void tearDown ();
protected:
ARDOUR::Session* _session;
};

View File

@ -0,0 +1,37 @@
#include "pbd/receiver.h"
class TestReceiver : public Receiver
{
protected:
void receive (Transmitter::Channel chn, const char * str) {
const char *prefix = "";
switch (chn) {
case Transmitter::Error:
prefix = ": [ERROR]: ";
break;
case Transmitter::Info:
/* ignore */
return;
case Transmitter::Warning:
prefix = ": [WARNING]: ";
break;
case Transmitter::Fatal:
prefix = ": [FATAL]: ";
break;
case Transmitter::Throw:
/* this isn't supposed to happen */
abort ();
}
/* note: iostreams are already thread-safe: no external
lock required.
*/
std::cout << prefix << str << std::endl;
if (chn == Transmitter::Fatal) {
exit (9);
}
}
};

View File

@ -431,6 +431,8 @@ def build(bld):
test/framepos_plus_beats_test.cc
test/framepos_minus_beats_test.cc
test/playlist_layering_test.cc
test/playlist_overlap_cache_test.cc
test/test_needing_session.cc
test/testrunner.cc
'''.split()

View File

@ -21,8 +21,8 @@
</para>
<para>
Of course, nothing in digital audio is ever quite that simple, and so of
course there are some complications:
Of course, nothing in digital audio is ever quite that simple, and so
there are some complications:
</para>
<section id="layers-crossfades">
@ -38,14 +38,14 @@
<section id="region-opacity">
<title> Region Opacity </title>
<para>
In a perverse nod to image manipulation programs, Ardour allows you to
With a nod to image manipulation programs, Ardour allows you to
make regions transparent. By default, all regions are created opaque,
which means that when they are playing, no region below them are
audible. However, if you change the region to be transparent, the
region will be audible together with any regions below it. This
capability should probably not be abused - if you really want to mix
sounds together in this way, they should probably live in their own
tracks. Occasionally though, this can be useful trick.
capability should probably not be abused; if you really want to mix
sounds together in this way, they should probably be on their own
tracks. Occasionally though, this can be a useful trick.
</para>
<para>
@ -55,70 +55,74 @@
</para>
</section>
<section id="layering-styles">
<title> Layering Styles </title>
<para>
When you are recording new material for a track, its typical to want
to new material recorded "over" existing material in the track to be
what you hear on playback. For example, if you overdub part of a
guitar solo, you normally want the overdub to be audible, not hidden
by the old version that was already there. By contrast, when editing
using splitting/trimming/moving of regions to create a particular
arrangement along the timeline, many people find that they want
regions that start later on the timeline to be the ones that are
audible.
</para>
<section id="choice-of-layering">
<title>Choice of layering</title>
<para>
To facilitate these two contradictory desires, Ardour features three
different styles for assigning regions to layers.
There are two main decisions to be made with regard to how a playlist
should be layered:
</para>
<variablelist>
<title></title>
<varlistentry>
<term>Most recently added regions are higher</term>
<listitem>
<para>
Use this style when recording/overdubbing new material. Edits of
any kind do not modify the layering.
</para>
</listitem>
Given overlapping regions, which order should they be layered in?
</varlistentry>
<varlistentry>
<term>Most recently added/moved/trimmed regions are higher</term>
<listitem>
<para>
Use this style when recording/overdubbing new material, but you
want basic edits to cause regions to rise to the top.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Later regions are higher</term>
<listitem>
<para>
Use this style when rearranging and editing regions.
</para>
</listitem>
When should layering be changed?
</varlistentry>
</variablelist>
<section id="layering-order">
<title>Layering Order</title>
<para>
Ardour provides three-and-a-half ways to decide on the order in which regions are layered. The most basic choice is:
</para>
<variablelist>
<title></title>
<varlistentry>
<term>Most recently added regions are higher</term>
<listitem>
<para>
Regions which are later in time will be on higher layers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Most recently added or edited regions are higher</term>
<listitem>
<para>
Regions which were more recently edited or added to the playlist
will be on higher layers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Later regions are higher</term>
<listitem>
<para>
Regions which were more recently added to the playlist will be on higher
layers.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<para>
A new session has the layering style set to "Most recently
added/moved/trimmed regions are higher". To change the layering style,
open the <emphasis>options editor</emphasis> and select the
"Layers&amp;Fades" page. There is an option there to select the style
you want. Layering style may be changed at any time. The existing
layering of all playlists is not changed when changing the layering
model.
A new session has the layering style set to "Most recently edited or
added regions are higher". To change the layering style, open the
<emphasis>Session Properties</emphasis> dialogue and choose your layering
style from the "Misc" page. Changing the layering style only affects
future edits to the playlist; the existing layering of all playlists is
preserved when changing the layering mode.
</para>
</section>
<section id="modifying-layering-by-hand">
<title> Modifying Layering By Hand </title>
<title>Modifying Layering Explicitly</title>
<para>
If you want a particular region to be the uppermost when the current
layering style has put it on a lower layer, context click on the