Revert internals of the last layering-related commit, and go back a slightly-cleaned-up version of how it was before. Remove all layering modes; only option now is add-is-higher. Move-add-higher could easily be re-added if anyone uses it.
git-svn-id: svn://localhost/ardour2/branches/3.0@11111 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
cabb76cce6
commit
b177514930
@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
for f in basic-layering explicit-layering1 explicit-layering2 tricky-explicit-layering; do
|
||||
for f in basic-layering layering-order-1 layering-order-2; do
|
||||
echo "$f"
|
||||
inkscape -z --export-area-drawing -f $f.svg --export-pdf $f.pdf
|
||||
done
|
||||
|
||||
|
@ -1,322 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 13 KiB |
@ -1,322 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 13 KiB |
201
doc/layering/layering-order-1.svg
Normal file
201
doc/layering/layering-order-1.svg
Normal file
@ -0,0 +1,201 @@
|
||||
<?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.48.2 r9819"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path3913"
|
||||
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(0.6) rotate(180) translate(0,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.4179431"
|
||||
inkscape:cx="170.5"
|
||||
inkscape:cy="941"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="949"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1" />
|
||||
<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">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#00ff00;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"
|
||||
id="rect2985"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="78.1614"
|
||||
y="21.362185" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff0003;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"
|
||||
id="rect2985-7"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="117.60985"
|
||||
y="82.473022" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#0054ff;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"
|
||||
id="rect2985-7-4"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="200.92497"
|
||||
y="51.917603" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#fff400;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"
|
||||
id="rect2985-7-0"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="42.5"
|
||||
y="113.02844" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff00de;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"
|
||||
id="rect2985-7-0-5"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="123.29042"
|
||||
y="143.58386" />
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff7100;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"
|
||||
id="rect2985-7-0-5-5"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="221.75375"
|
||||
y="174.13928" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="255.11232"
|
||||
y="193.33777"
|
||||
id="text3857"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3859"
|
||||
x="255.11232"
|
||||
y="193.33777">0</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="156.577"
|
||||
y="162.39966"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="156.577"
|
||||
y="162.39966">1</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="75.858574"
|
||||
y="131.84424"
|
||||
id="text3865"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3867"
|
||||
x="75.858574"
|
||||
y="131.84424">2</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="150.96841"
|
||||
y="101.16282"
|
||||
id="text3869"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3871"
|
||||
x="150.96841"
|
||||
y="101.16282">3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="234.28354"
|
||||
y="70.793404"
|
||||
id="text3873"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3875"
|
||||
x="234.28354"
|
||||
y="70.793404">4</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="111.51997"
|
||||
y="40.045986"
|
||||
id="text3877"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3879"
|
||||
x="111.51997"
|
||||
y="40.045986">5</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
|
||||
d="m 324.24253,185.09612 0,-149.300453"
|
||||
id="path3881"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="330.85974"
|
||||
y="98.245438"
|
||||
id="text4327"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4329"
|
||||
x="330.85974"
|
||||
y="98.245438">increasing</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="330.85974"
|
||||
y="113.24544"
|
||||
id="tspan4331">layering</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="330.85974"
|
||||
y="128.24544"
|
||||
id="tspan4333">order</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.5 KiB |
240
doc/layering/layering-order-2.svg
Normal file
240
doc/layering/layering-order-2.svg
Normal file
@ -0,0 +1,240 @@
|
||||
<?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.48.2 r9819"
|
||||
sodipodi:docname="layer-order-2.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path3913"
|
||||
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(0.6) rotate(180) translate(0,0)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.4179431"
|
||||
inkscape:cx="170.5"
|
||||
inkscape:cy="941"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="949"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1" />
|
||||
<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">
|
||||
<g
|
||||
id="g4432">
|
||||
<g
|
||||
id="g4403">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff7100;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"
|
||||
id="rect2985-7-0-5-5"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="221.75375"
|
||||
y="174.13928" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="255.11232"
|
||||
y="193.33777"
|
||||
id="text3857"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3859"
|
||||
x="255.11232"
|
||||
y="193.33777">0</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,30.55542)"
|
||||
id="g4398">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff00de;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"
|
||||
id="rect2985-7-0-5"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="123.29042"
|
||||
y="143.58386" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="156.577"
|
||||
y="162.39966"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="156.577"
|
||||
y="162.39966">1</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,61.11084)"
|
||||
id="g4393">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#fff400;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"
|
||||
id="rect2985-7-0"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="42.5"
|
||||
y="113.02844" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="75.858574"
|
||||
y="131.84424"
|
||||
id="text3865"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3867"
|
||||
x="75.858574"
|
||||
y="131.84424">2</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4421"
|
||||
transform="translate(0,0.38900757)">
|
||||
<g
|
||||
transform="translate(0,55.00543)"
|
||||
id="g4388">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#ff0003;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"
|
||||
id="rect2985-7"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="117.60985"
|
||||
y="82.473022" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="150.96841"
|
||||
y="101.16282"
|
||||
id="text3869"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3871"
|
||||
x="150.96841"
|
||||
y="101.16282">3</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,85.56085)"
|
||||
id="g4382">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#0054ff;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"
|
||||
id="rect2985-7-4"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="200.92497"
|
||||
y="51.917603" />
|
||||
<g
|
||||
id="g4378">
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3873"
|
||||
y="70.793404"
|
||||
x="234.28354"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
xml:space="preserve"><tspan
|
||||
y="70.793404"
|
||||
x="234.28354"
|
||||
id="tspan3875"
|
||||
sodipodi:role="line">4</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4446">
|
||||
<g
|
||||
transform="translate(0,80.233484)"
|
||||
id="g4414">
|
||||
<g
|
||||
id="g4408">
|
||||
<g
|
||||
id="g4373">
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:#00ff00;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"
|
||||
id="rect2985"
|
||||
width="72.585144"
|
||||
height="29.6516"
|
||||
x="78.1614"
|
||||
y="21.362185" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="111.51997"
|
||||
y="40.045986"
|
||||
id="text3877"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3879"
|
||||
x="111.51997"
|
||||
y="40.045986">5</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
|
||||
d="m 324.24253,185.09612 0,-78.57919"
|
||||
id="path3881"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:LMRoman12;-inkscape-font-specification:LMRoman12"
|
||||
x="330.85974"
|
||||
y="140.01648"
|
||||
id="text4327"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4329"
|
||||
x="330.85974"
|
||||
y="140.01648">increasing</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="330.85974"
|
||||
y="155.01648"
|
||||
id="tspan4333">layer</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.7 KiB |
@ -1,19 +1,19 @@
|
||||
\documentclass{article}
|
||||
\title{Region Layering}
|
||||
\title{Region layering}
|
||||
\author{}
|
||||
\date{}
|
||||
|
||||
\usepackage{graphicx}
|
||||
\usepackage{graphicx,amsmath}
|
||||
\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.
|
||||
played.
|
||||
|
||||
|
||||
\subsection{Layers}
|
||||
\section{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
|
||||
@ -37,114 +37,168 @@ This follows the basic rule that, at any given point, the region on
|
||||
the highest layer will be played.
|
||||
|
||||
|
||||
\section{Choice of layering}
|
||||
\section{Which layer does a region go on?}
|
||||
|
||||
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}
|
||||
The logic to decide which layer a region goes onto is somewhat complicated.
|
||||
This section describes it in hand-wavey and more technical terms.
|
||||
|
||||
|
||||
\subsection{Layering order}
|
||||
\subsection{Hand-wavey description}
|
||||
|
||||
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}.
|
||||
A playlist maintains an internal \emph{layering order} for regions. This order
|
||||
is not directly visible in Ardour, but it's useful to understand it
|
||||
nonetheless. Figure~\ref{fig:layering-order-1} gives a rough idea of what this
|
||||
means.
|
||||
|
||||
\begin{figure}[ht]
|
||||
\begin{center}
|
||||
\includegraphics{explicit-layering1.pdf}
|
||||
\includegraphics{layering-order-1.pdf}
|
||||
\end{center}
|
||||
\caption{Explicit layering: stage 1}
|
||||
\label{fig:explicit-layering1}
|
||||
\caption{Layering order}
|
||||
\label{fig:layering-order-1}
|
||||
\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}.
|
||||
Here we see 6 regions; as the layering order value increases, the region will
|
||||
be placed on a higher layer.
|
||||
|
||||
Every time any region is moved, added or edited, a \emph{relayer} occurs. This
|
||||
collapses the regions down into layers. For our example, this would result in
|
||||
the arrangement in Figure~\ref{fig:layering-order-2}.
|
||||
|
||||
\begin{figure}[ht]
|
||||
\begin{center}
|
||||
\includegraphics{explicit-layering2.pdf}
|
||||
\includegraphics{layering-order-2.pdf}
|
||||
\end{center}
|
||||
\caption{Explicit layering: stage 2}
|
||||
\label{fig:explicit-layering2}
|
||||
\caption{Layering}
|
||||
\label{fig:layering-order-2}
|
||||
\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}.
|
||||
The relayer operation takes each region, in the layering order, and puts it
|
||||
on the lowest possible layer that it can be on without overlap.
|
||||
|
||||
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}.
|
||||
\subsubsection{Layering order}
|
||||
|
||||
Given that arrangement, the remaining question is how the layering order is
|
||||
arrived at. The rules are as follows:
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\item When a region is added to a playlist, it goes above the current highest
|
||||
region in the layering order.
|
||||
|
||||
\item In `overlaid' track mode, moving or editing regions does not change the
|
||||
layering order. Hence, moving regions about will maintain their position in
|
||||
the layering order. Changing overlaps may change the \emph{layer} that the
|
||||
region ends up on, but not the order in which they will be layered.
|
||||
|
||||
\item In `stacked' track mode, moving regions places the region on the layer
|
||||
that they are dropped on. This is achieved by modifying the layering order
|
||||
for the region that is moved, so that when the relayer operation happens the
|
||||
region ends up on the desired layer.
|
||||
|
||||
\item When regions are `raised' or `lowered' in the stack, the layering order
|
||||
is modified to achieve the desired layer change.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
The upshot of all this is that regions should maintain their expected layering
|
||||
order, unless that order is explicitly change using `stacked' mode or by
|
||||
explicit layering commands like `raise' or `lower'.
|
||||
|
||||
|
||||
|
||||
\subsection{Technical description}
|
||||
|
||||
Each region on a playlist has three layering-related properties: its current
|
||||
layer $c$ (an integer) and its layering index $i$ (also an integer). It also
|
||||
has an \emph{optional} pending layer $p$ which is fractional.
|
||||
|
||||
Whenever a region is added, moved, trimmed, etc.\ we run a \emph{relayer}. This
|
||||
does the following:
|
||||
|
||||
\begin{enumerate}
|
||||
\item Take a list of all regions and remove those who have a value for $p$.
|
||||
\item Sort the remainder in ascending order of $i$.
|
||||
\item Insert the regions which have a value for $p$ in the correct place in the
|
||||
list by comparing $c$ of those in the list to $p$ of the inserted region.
|
||||
\item Iterate over the resulting list, putting each region on the lowest available
|
||||
layer, setting its current layer $c$, and clearing $p$.
|
||||
\item If any region had a pending layer, iterate through the region list again
|
||||
giving each region a new layering index $i$ ascending from 0.
|
||||
\end{enumerate}
|
||||
|
||||
The pending layer $p$ is set up in the following situations:
|
||||
\begin{enumerate}
|
||||
\item When a region is added to the playlist, $p$ is set to $\infty$.
|
||||
\item When a region is raised to the top of the playlist, $p$ is set to $\infty$.
|
||||
\item When a region is raised one step in the playlist, $p$ is set to $c + 1.5$.
|
||||
\item When a region is lowered to the bottom of the playlist, $p$ is set to $-0.5$.
|
||||
\item When a region is lowered one step int the playlist, $p$ is set to $c - 1.5$.
|
||||
\item When a region is explicitly put between layers $A$ and $B$ in `stacked'
|
||||
mode, $p$ is set to $(A + B) / 2$.
|
||||
\end{enumerate}
|
||||
|
||||
The idea of this approach is that the layering indices $i$ are used to keep a
|
||||
current state of the stack, and this state is used to maintain region
|
||||
relationships. Setting $p$ will alter these relationships, after which the
|
||||
layering indices $i$ are updated to reflect the new status quo.
|
||||
|
||||
It is not sufficient to use current layer $c$ as the state of the stack.
|
||||
Consider two overlapping regions $P$ and $Q$, with $P$ on layer~0 and $Q$ on
|
||||
layer~1. Now raise $P$ to the top of the stack, so that $Q$ is on layer~0 and
|
||||
$P$ on layer~1. Move $P$ away from $Q$ (in overlaid mode) so that both regions
|
||||
are on layer~0. Now drag $P$ back over $Q$. One would expect $P$ to return to
|
||||
the top of the stack, since it was explicitly raised earlier. However, if the
|
||||
relayer operation were to compare $c$ for each region, they would be identical;
|
||||
the information that $P$ was once higher than $Q$ has been lost.
|
||||
|
||||
|
||||
\section{Stacked mode}
|
||||
|
||||
When a track is being displayed in \emph{stacked} mode, regions are spread out
|
||||
vertically to indicate their layering, like in Figure~\ref{fig:stacked}.
|
||||
|
||||
\begin{figure}[ht]
|
||||
\begin{center}
|
||||
\includegraphics{tricky-explicit-layering.pdf}
|
||||
\includegraphics[scale=0.5]{stacked.png}
|
||||
\end{center}
|
||||
\caption{More complex explicit layering}
|
||||
\label{fig:tricky-explicit-layering}
|
||||
\caption{A track in stacked mode}
|
||||
\label{fig:stacked}
|
||||
\end{figure}
|
||||
|
||||
% XXX: this makes no sense
|
||||
In this mode, layering is performed \emph{explicitly}. In other words, the
|
||||
user's immediate actions decide which layer a region should be put on. When a
|
||||
region move drag is started in stacked mode, the regions separate further out
|
||||
vertically, to leave space between each layer, as shown in
|
||||
Figure~\ref{fig:stacked-drag}.
|
||||
|
||||
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.
|
||||
\begin{figure}[ht]
|
||||
\begin{center}
|
||||
\includegraphics[scale=0.5]{stacked-drag.png}
|
||||
\end{center}
|
||||
\caption{A track in stacked mode during a drag}
|
||||
\label{fig:stacked-drag}
|
||||
\end{figure}
|
||||
|
||||
The region(s) being dragged can then be dropped in any location, horizontally
|
||||
and vertically, and the regions will be layered accordingly.
|
||||
|
||||
|
||||
\section{Overlaid mode}
|
||||
|
||||
When a track is being displayed in \emph{overlaid} mode, regions are
|
||||
displayed on top of one another, like in Figure~\ref{fig:overlaid}.
|
||||
|
||||
\begin{figure}[ht]
|
||||
\begin{center}
|
||||
\includegraphics[scale=0.5]{overlaid.png}
|
||||
\end{center}
|
||||
\caption{A track in overlaid mode}
|
||||
\label{fig:overlaid}
|
||||
\end{figure}
|
||||
|
||||
In this mode, drags of regions maintain the same \emph{layer ordering}, even if the layers may
|
||||
change.
|
||||
|
||||
\end{document}
|
||||
|
@ -1,323 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 13 KiB |
@ -812,7 +812,7 @@ AudioStreamView::update_content_height (CrossfadeView* cv)
|
||||
switch (_layer_display) {
|
||||
case Overlaid:
|
||||
cv->set_y (0);
|
||||
cv->set_height (height);
|
||||
cv->set_heights (height, height);
|
||||
break;
|
||||
|
||||
case Stacked:
|
||||
@ -827,10 +827,10 @@ AudioStreamView::update_content_height (CrossfadeView* cv)
|
||||
|
||||
if (_layer_display == Stacked) {
|
||||
cv->set_y ((_layers - high - 1) * h);
|
||||
cv->set_height ((high - low + 1) * h);
|
||||
cv->set_heights ((high - low + 1) * h, h);
|
||||
} else {
|
||||
cv->set_y (((_layers - high) * 2 - 1) * h);
|
||||
cv->set_height (((high - low) * 2 + 1) * h);
|
||||
cv->set_heights (((high - low) * 2 + 1) * h, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
|
||||
crossfade (xf),
|
||||
left_view (lview),
|
||||
right_view (rview),
|
||||
_all_in_view (false)
|
||||
_all_in_view (false),
|
||||
_child_height (0)
|
||||
{
|
||||
_valid = true;
|
||||
_visible = true;
|
||||
@ -109,13 +110,15 @@ CrossfadeView::reset_width_dependent_items (double pixel_width)
|
||||
}
|
||||
|
||||
void
|
||||
CrossfadeView::set_height (double h)
|
||||
CrossfadeView::set_heights (double fade_height, double child_height)
|
||||
{
|
||||
if (h > TimeAxisView::preset_height (HeightSmall)) {
|
||||
h -= NAME_HIGHLIGHT_SIZE;
|
||||
if (child_height > TimeAxisViewItem::NAME_HIGHLIGHT_THRESH) {
|
||||
fade_height -= NAME_HIGHLIGHT_SIZE;
|
||||
child_height -= NAME_HIGHLIGHT_SIZE;
|
||||
}
|
||||
|
||||
TimeAxisViewItem::set_height (h);
|
||||
TimeAxisViewItem::set_height (fade_height);
|
||||
_child_height = child_height;
|
||||
|
||||
redraw_curves ();
|
||||
}
|
||||
@ -203,7 +206,9 @@ CrossfadeView::redraw_curves ()
|
||||
for (int i = 0, pci = 0; i < npoints; ++i) {
|
||||
Art::Point &p = (*points)[pci++];
|
||||
p.set_x (xoff + i + 1);
|
||||
p.set_y (_height - ((_height - 2) * vec[i]));
|
||||
|
||||
double const ho = crossfade->in()->layer() > crossfade->out()->layer() ? _child_height : _height;
|
||||
p.set_y (ho - ((_child_height - 2) * vec[i]));
|
||||
}
|
||||
|
||||
fade_in->property_points() = *points;
|
||||
@ -213,7 +218,9 @@ CrossfadeView::redraw_curves ()
|
||||
for (int i = 0, pci = 0; i < npoints; ++i) {
|
||||
Art::Point &p = (*points)[pci++];
|
||||
p.set_x (xoff + i + 1);
|
||||
p.set_y (_height - ((_height - 2) * vec[i]));
|
||||
|
||||
double const ho = crossfade->in()->layer() < crossfade->out()->layer() ? _child_height : _height;
|
||||
p.set_y (ho - ((_child_height - 2) * vec[i]));
|
||||
}
|
||||
|
||||
fade_out->property_points() = *points;
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
AudioRegionView& left_view; // and these too
|
||||
AudioRegionView& right_view;
|
||||
|
||||
void set_height (double);
|
||||
void set_heights (double, double);
|
||||
|
||||
bool valid() const { return _valid; }
|
||||
bool visible() const { return _visible; }
|
||||
@ -68,6 +68,7 @@ private:
|
||||
bool _valid;
|
||||
bool _visible;
|
||||
bool _all_in_view;
|
||||
double _child_height;
|
||||
|
||||
ArdourCanvas::Line *fade_in;
|
||||
ArdourCanvas::Line *fade_out;
|
||||
|
@ -2475,7 +2475,7 @@ Editor::get_state ()
|
||||
/** @param y y offset from the top of all trackviews.
|
||||
* @return pair: TimeAxisView that y is over, layer index.
|
||||
* TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
|
||||
* in stacked region display mode, otherwise 0.
|
||||
* in stacked or expanded region display mode, otherwise 0.
|
||||
*/
|
||||
std::pair<TimeAxisView *, double>
|
||||
Editor::trackview_by_y_position (double y)
|
||||
|
@ -488,10 +488,6 @@ RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
|
||||
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
|
||||
@ -578,7 +574,6 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
|
||||
/* 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.
|
||||
@ -599,6 +594,10 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
||||
/* Find the TimeAxisView that the pointer is now over */
|
||||
pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
|
||||
|
||||
if (first_move && tv.first->view()->layer_display() == Stacked) {
|
||||
tv.first->view()->set_layer_display (Expanded);
|
||||
}
|
||||
|
||||
/* Bail early if we're not over a track */
|
||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
|
||||
if (!rtv || !rtv->is_track()) {
|
||||
@ -647,6 +646,11 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
||||
|
||||
rv->get_time_axis_view().hide_dependent_views (*rv);
|
||||
|
||||
/* Absolutely no idea why this is necessary, but it is; without
|
||||
it, the region view disappears after the reparent.
|
||||
*/
|
||||
_editor->update_canvas_now ();
|
||||
|
||||
/* Reparent to a non scrolling group so that we can keep the
|
||||
region selection above all time axis views.
|
||||
Reparenting means that we will have to move the region view
|
||||
@ -656,11 +660,6 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
|
||||
rv->get_canvas_group()->reparent (*(_editor->_region_motion_group));
|
||||
|
||||
rv->fake_set_opaque (true);
|
||||
|
||||
if (!rv->get_time_axis_view().hidden()) {
|
||||
/* the track that this region view is on is hidden, so hide the region too */
|
||||
rv->get_canvas_group()->hide ();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have moved tracks, we'll fudge the layer delta so that the
|
||||
@ -832,6 +831,7 @@ void
|
||||
RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
|
||||
{
|
||||
RegionMotionDrag::finished (ev, movement_occurred);
|
||||
|
||||
if (!movement_occurred) {
|
||||
/* just a click */
|
||||
return;
|
||||
@ -965,9 +965,6 @@ RegionMoveDrag::finished_no_copy (
|
||||
RegionSelection new_views;
|
||||
PlaylistSet modified_playlists;
|
||||
PlaylistSet frozen_playlists;
|
||||
|
||||
list<pair<boost::shared_ptr<Region>, double> > pending_explicit_relayers;
|
||||
Playlist::RegionList pending_implicit_relayers;
|
||||
set<RouteTimeAxisView*> views_to_update;
|
||||
|
||||
if (_brushing) {
|
||||
@ -1049,12 +1046,8 @@ RegionMoveDrag::finished_no_copy (
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
|
||||
|
||||
bool const explicit_relayer = dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded;
|
||||
|
||||
if (explicit_relayer) {
|
||||
pending_explicit_relayers.push_back (make_pair (rv->region (), dest_layer));
|
||||
} else {
|
||||
pending_implicit_relayers.push_back (rv->region ());
|
||||
if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
|
||||
rv->region()->set_pending_layer (dest_layer);
|
||||
}
|
||||
|
||||
/* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
|
||||
@ -1063,7 +1056,6 @@ RegionMoveDrag::finished_no_copy (
|
||||
|
||||
if (r.second) {
|
||||
playlist->freeze ();
|
||||
playlist->suspend_relayer ();
|
||||
}
|
||||
|
||||
/* this movement may result in a crossfade being modified, so we need to get undo
|
||||
@ -1119,22 +1111,8 @@ RegionMoveDrag::finished_no_copy (
|
||||
_editor->selection->set (new_views);
|
||||
}
|
||||
|
||||
/* We can't use the normal mechanism for relayering, as some regions may require an explicit relayer
|
||||
rather than an implicit one. So we thaw before resuming relayering, then do the relayers
|
||||
that we require.
|
||||
*/
|
||||
|
||||
for (PlaylistSet::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
|
||||
for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
|
||||
(*p)->thaw();
|
||||
(*p)->resume_relayer ();
|
||||
}
|
||||
|
||||
for (list<pair<boost::shared_ptr<Region>, double> >::iterator i = pending_explicit_relayers.begin(); i != pending_explicit_relayers.end(); ++i) {
|
||||
i->first->playlist()->relayer (i->first, i->second);
|
||||
}
|
||||
|
||||
for (Playlist::RegionList::iterator i = pending_implicit_relayers.begin(); i != pending_implicit_relayers.end(); ++i) {
|
||||
(*i)->playlist()->relayer (*i);
|
||||
}
|
||||
|
||||
/* write commands for the accumulated diffs for all our modified playlists */
|
||||
@ -1144,9 +1122,9 @@ RegionMoveDrag::finished_no_copy (
|
||||
|
||||
/* We have futzed with the layering of canvas items on our streamviews.
|
||||
If any region changed layer, this will have resulted in the stream
|
||||
views being asked to set up their region views, and all will be
|
||||
well. If not, we might now have badly-ordered region views. Ask
|
||||
the Streamviews involved to sort themselves out, just in case.
|
||||
views being asked to set up their region views, and all will be well.
|
||||
If not, we might now have badly-ordered region views. Ask the StreamViews
|
||||
involved to sort themselves out, just in case.
|
||||
*/
|
||||
|
||||
for (set<RouteTimeAxisView*>::iterator i = views_to_update.begin(); i != views_to_update.end(); ++i) {
|
||||
@ -1214,7 +1192,7 @@ RegionMoveDrag::insert_region_into_playlist (
|
||||
dest_playlist->add_region (region, where);
|
||||
|
||||
if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
|
||||
dest_playlist->relayer (region, dest_layer);
|
||||
region->set_pending_layer (dest_layer);
|
||||
}
|
||||
|
||||
c.disconnect ();
|
||||
|
@ -249,7 +249,7 @@ struct DraggingView
|
||||
* or -1 if it is not visible.
|
||||
*/
|
||||
int time_axis_view;
|
||||
/** Layer that this region is currently being displayed on. This is a double
|
||||
/** 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.
|
||||
*/
|
||||
|
@ -262,29 +262,6 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
||||
|
||||
/* Misc */
|
||||
|
||||
add_option (_("Misc"), new OptionEditorHeading (_("Layering (in overlaid mode)")));
|
||||
|
||||
ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
|
||||
"layer-model",
|
||||
_("Layering model"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_layer_model),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_layer_model)
|
||||
);
|
||||
|
||||
lm->add (LaterHigher, _("later 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")));
|
||||
|
||||
add_option (_("Misc"), new BoolOption (
|
||||
|
@ -181,7 +181,7 @@ StreamView::add_region_view (boost::weak_ptr<Region> wr)
|
||||
|
||||
add_region_view_internal (r, true);
|
||||
|
||||
if (_layer_display == Stacked) {
|
||||
if (_layer_display == Stacked || _layer_display == Expanded) {
|
||||
update_contents_height ();
|
||||
}
|
||||
}
|
||||
@ -301,7 +301,7 @@ StreamView::playlist_layered (boost::weak_ptr<Track> wtr)
|
||||
_layers = tr->playlist()->top_layer() + 1;
|
||||
}
|
||||
|
||||
if (_layer_display == Stacked || _layer_display == Expanded) {
|
||||
if (_layer_display == Stacked) {
|
||||
update_contents_height ();
|
||||
update_coverage_frames ();
|
||||
} else {
|
||||
|
@ -1196,7 +1196,7 @@ TimeAxisView::color_handler ()
|
||||
* If the covering object is a child axis, then the child is returned.
|
||||
* TimeAxisView is 0 otherwise.
|
||||
* Layer index is the layer number (possibly fractional) if the TimeAxisView is valid
|
||||
* and is in stacked or expanded region display mode, otherwise 0.
|
||||
* and is in stacked or expanded * region display mode, otherwise 0.
|
||||
*/
|
||||
std::pair<TimeAxisView*, double>
|
||||
TimeAxisView::covers_y_position (double y)
|
||||
@ -1215,7 +1215,7 @@ TimeAxisView::covers_y_position (double y)
|
||||
case Stacked:
|
||||
if (view ()) {
|
||||
/* compute layer */
|
||||
l = floor ((_y_position + height - y) / (view()->child_height ()));
|
||||
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 ()) {
|
||||
@ -1225,7 +1225,7 @@ TimeAxisView::covers_y_position (double y)
|
||||
break;
|
||||
case Expanded:
|
||||
if (view ()) {
|
||||
int n = floor ((_y_position + height - y) / (view()->child_height ()));
|
||||
int const 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;
|
||||
|
@ -44,9 +44,6 @@
|
||||
#include "ardour/session_object.h"
|
||||
#include "ardour/data_type.h"
|
||||
|
||||
class PlaylistOverlapCacheTest;
|
||||
class PlaylistLayeringTest;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
@ -225,10 +222,7 @@ 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>);
|
||||
void relayer (boost::shared_ptr<Region>, double);
|
||||
void suspend_relayer ();
|
||||
void resume_relayer ();
|
||||
uint64_t highest_layering_index () const;
|
||||
|
||||
protected:
|
||||
friend class Session;
|
||||
@ -355,7 +349,7 @@ 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);
|
||||
|
||||
void relayer (RegionList const &);
|
||||
void relayer ();
|
||||
|
||||
void begin_undo ();
|
||||
void end_undo ();
|
||||
@ -382,71 +376,6 @@ 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 */
|
||||
|
@ -65,6 +65,7 @@ namespace Properties {
|
||||
extern PBD::PropertyDescriptor<float> stretch;
|
||||
extern PBD::PropertyDescriptor<float> shift;
|
||||
extern PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
|
||||
extern PBD::PropertyDescriptor<uint64_t> layering_index;
|
||||
};
|
||||
|
||||
class Playlist;
|
||||
@ -112,7 +113,6 @@ 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;
|
||||
@ -202,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 should call this */
|
||||
void set_layer (layer_t l); /* ONLY Playlist can call this */
|
||||
void raise ();
|
||||
void lower ();
|
||||
void raise_to_top ();
|
||||
@ -252,8 +252,8 @@ class Region
|
||||
|
||||
virtual boost::shared_ptr<Region> get_parent() const;
|
||||
|
||||
uint64_t last_layer_op (LayerOp) const;
|
||||
void set_last_layer_op (LayerOp, uint64_t);
|
||||
uint64_t layering_index () const { return _layering_index; }
|
||||
void set_layering_index (uint64_t when) { _layering_index = when; }
|
||||
|
||||
virtual bool is_dependent() const { return false; }
|
||||
virtual bool depends_on (boost::shared_ptr<Region> /*other*/) const { return false; }
|
||||
@ -294,12 +294,11 @@ class Region
|
||||
|
||||
void invalidate_transients ();
|
||||
|
||||
void drop_sources ();
|
||||
void set_pending_layer (double);
|
||||
bool reset_pending_layer ();
|
||||
boost::optional<double> pending_layer () const;
|
||||
|
||||
/** @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);
|
||||
}
|
||||
void drop_sources ();
|
||||
|
||||
protected:
|
||||
friend class RegionFactory;
|
||||
@ -384,18 +383,15 @@ class Region
|
||||
PBD::Property<float> _stretch;
|
||||
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;
|
||||
PBD::Property<uint64_t> _layering_index;
|
||||
|
||||
framecnt_t _last_length;
|
||||
framepos_t _last_position;
|
||||
mutable RegionEditState _first_edit;
|
||||
Timecode::BBT_Time _bbt_time;
|
||||
|
||||
boost::optional<double> _pending_layer;
|
||||
|
||||
void register_properties ();
|
||||
|
||||
void use_sources (SourceList const &);
|
||||
|
@ -36,22 +36,6 @@ struct RegionSortByLayer {
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif /* __libardour_region_sorters_h__ */
|
||||
|
@ -47,8 +47,6 @@ 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", 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)
|
||||
|
@ -409,12 +409,6 @@ namespace ARDOUR {
|
||||
ShortCrossfade
|
||||
};
|
||||
|
||||
enum LayerModel {
|
||||
LaterHigher,
|
||||
AddOrBoundsChangeHigher,
|
||||
AddHigher
|
||||
};
|
||||
|
||||
enum ListenPosition {
|
||||
AfterFaderListen,
|
||||
PreFaderListen
|
||||
@ -592,11 +586,6 @@ namespace ARDOUR {
|
||||
FadeLogB
|
||||
};
|
||||
|
||||
enum LayerOp {
|
||||
LayerOpAdd,
|
||||
LayerOpBoundsChange
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
|
||||
@ -613,7 +602,6 @@ std::istream& operator>>(std::istream& o, ARDOUR::PFLPosition& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::AFLPosition& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::RemoteModel& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::ListenPosition& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::LayerModel& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::InsertMergePolicy& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf);
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::SyncSource& sf);
|
||||
@ -634,7 +622,6 @@ std::ostream& operator<<(std::ostream& o, const ARDOUR::PFLPosition& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::AFLPosition& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::RemoteModel& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::ListenPosition& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::LayerModel& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::InsertMergePolicy& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::CrossfadeModel& sf);
|
||||
std::ostream& operator<<(std::ostream& o, const ARDOUR::SyncSource& sf);
|
||||
|
@ -1510,6 +1510,8 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
||||
}
|
||||
|
||||
i_am_the_modifier++;
|
||||
|
||||
region->set_pending_layer (max_layer);
|
||||
_playlist->add_region (region, (*ci)->start, 1, non_layered());
|
||||
i_am_the_modifier--;
|
||||
|
||||
|
@ -73,7 +73,6 @@ setup_enum_writer ()
|
||||
RemoteModel _RemoteModel;
|
||||
DenormalModel _DenormalModel;
|
||||
CrossfadeModel _CrossfadeModel;
|
||||
LayerModel _LayerModel;
|
||||
InsertMergePolicy _InsertMergePolicy;
|
||||
ListenPosition _ListenPosition;
|
||||
SampleFormat _SampleFormat;
|
||||
@ -264,11 +263,6 @@ setup_enum_writer ()
|
||||
REGISTER_ENUM (ShortCrossfade);
|
||||
REGISTER (_CrossfadeModel);
|
||||
|
||||
REGISTER_ENUM (LaterHigher);
|
||||
REGISTER_ENUM (AddOrBoundsChangeHigher);
|
||||
REGISTER_ENUM (AddHigher);
|
||||
REGISTER (_LayerModel);
|
||||
|
||||
REGISTER_ENUM (InsertMergeReject);
|
||||
REGISTER_ENUM (InsertMergeRelax);
|
||||
REGISTER_ENUM (InsertMergeReplace);
|
||||
@ -711,19 +705,6 @@ std::ostream& operator<<(std::ostream& o, const ListenPosition& var)
|
||||
std::string s = enum_2_string (var);
|
||||
return o << s;
|
||||
}
|
||||
std::istream& operator>>(std::istream& o, LayerModel& var)
|
||||
{
|
||||
std::string s;
|
||||
o >> s;
|
||||
var = (LayerModel) string_2_enum (s, var);
|
||||
return o;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const LayerModel& var)
|
||||
{
|
||||
std::string s = enum_2_string (var);
|
||||
return o << s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream& o, InsertMergePolicy& var)
|
||||
{
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include "pbd/convert.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
#include "pbd/stateful_diff_command.h"
|
||||
#include "pbd/xml++.h"
|
||||
|
||||
@ -187,8 +186,6 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
|
||||
in_partition = false;
|
||||
subcnt = 0;
|
||||
_frozen = other->_frozen;
|
||||
|
||||
layer_op_counter = other->layer_op_counter;
|
||||
}
|
||||
|
||||
Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, framecnt_t cnt, string str, bool hide)
|
||||
@ -256,6 +253,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, f
|
||||
plist.add (Properties::length, len);
|
||||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::layer, region->layer());
|
||||
plist.add (Properties::layering_index, region->layering_index());
|
||||
|
||||
new_region = RegionFactory::RegionFactory::create (region, plist);
|
||||
|
||||
@ -318,9 +316,7 @@ Playlist::init (bool hide)
|
||||
in_partition = false;
|
||||
subcnt = 0;
|
||||
_frozen = false;
|
||||
layer_op_counter = 0;
|
||||
_combine_ops = 0;
|
||||
_relayer_suspended = false;
|
||||
|
||||
_session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this));
|
||||
_session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this));
|
||||
@ -485,8 +481,6 @@ Playlist::notify_region_moved (boost::shared_ptr<Region> r)
|
||||
{
|
||||
Evoral::RangeMove<framepos_t> const move (r->last_position (), r->length (), r->position ());
|
||||
|
||||
/* We could timestamp the region's layer op here, but we're doing it in region_bounds_changed */
|
||||
|
||||
if (holding_state ()) {
|
||||
|
||||
pending_range_moves.push_back (move);
|
||||
@ -503,8 +497,6 @@ Playlist::notify_region_moved (boost::shared_ptr<Region> r)
|
||||
void
|
||||
Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
|
||||
{
|
||||
timestamp_layer_op (LayerOpBoundsChange, r);
|
||||
|
||||
if (r->position() >= r->last_position()) {
|
||||
/* trimmed shorter */
|
||||
return;
|
||||
@ -528,8 +520,6 @@ Playlist::notify_region_start_trimmed (boost::shared_ptr<Region> r)
|
||||
void
|
||||
Playlist::notify_region_end_trimmed (boost::shared_ptr<Region> r)
|
||||
{
|
||||
timestamp_layer_op (LayerOpBoundsChange, r);
|
||||
|
||||
if (r->length() < r->last_length()) {
|
||||
/* trimmed shorter */
|
||||
}
|
||||
@ -556,8 +546,6 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r)
|
||||
as though it could be.
|
||||
*/
|
||||
|
||||
timestamp_layer_op (LayerOpAdd, r);
|
||||
|
||||
if (holding_state()) {
|
||||
pending_adds.insert (r);
|
||||
pending_contents_change = true;
|
||||
@ -566,7 +554,6 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r)
|
||||
pending_contents_change = false;
|
||||
RegionAdded (boost::weak_ptr<Region> (r)); /* EMIT SIGNAL */
|
||||
ContentsChanged (); /* EMIT SIGNAL */
|
||||
relayer (r);
|
||||
}
|
||||
}
|
||||
|
||||
@ -584,35 +571,31 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
in_flush = true;
|
||||
|
||||
/* We have:
|
||||
|
||||
pending_bounds: regions whose bounds position and/or length changes
|
||||
pending_removes: regions which were removed
|
||||
pending_adds: regions which were added
|
||||
pending_length: true if the playlist length might have changed
|
||||
pending_contents_change: true if there was almost any change in the playlist
|
||||
pending_range_moves: details of periods of time that have been moved about (when regions have been moved)
|
||||
|
||||
*/
|
||||
|
||||
if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) {
|
||||
regions_changed = true;
|
||||
}
|
||||
|
||||
/* Make a list of regions that need relayering */
|
||||
RegionList regions_to_relayer;
|
||||
/* we have no idea what order the regions ended up in pending
|
||||
bounds (it could be based on selection order, for example).
|
||||
so, to preserve layering in the "most recently moved is higher"
|
||||
model, sort them by existing layer, then timestamp them.
|
||||
*/
|
||||
|
||||
// RegionSortByLayer cmp;
|
||||
// pending_bounds.sort (cmp);
|
||||
|
||||
for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
|
||||
regions_to_relayer.push_back (*r);
|
||||
dependent_checks_needed.insert (*r);
|
||||
}
|
||||
|
||||
for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
|
||||
remove_dependents (*s);
|
||||
// cerr << _name << " sends RegionRemoved\n";
|
||||
RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
|
||||
// cerr << _name << " sends RegionAdded\n";
|
||||
/* don't emit RegionAdded signal until relayering is done,
|
||||
so that the region is fully setup by the time
|
||||
anyone hear's that its been added
|
||||
@ -621,14 +604,18 @@ Playlist::flush_notifications (bool from_undo)
|
||||
}
|
||||
|
||||
if (regions_changed || pending_contents_change) {
|
||||
if (!in_set_state) {
|
||||
relayer ();
|
||||
}
|
||||
pending_contents_change = false;
|
||||
// cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl;
|
||||
ContentsChanged (); /* EMIT SIGNAL */
|
||||
// cerr << _name << "done contents change @ " << get_microseconds() << endl;
|
||||
}
|
||||
|
||||
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
|
||||
(*s)->clear_changes ();
|
||||
RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
|
||||
regions_to_relayer.push_back (*s);
|
||||
}
|
||||
|
||||
for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
|
||||
@ -643,14 +630,6 @@ Playlist::flush_notifications (bool from_undo)
|
||||
RegionsExtended (pending_region_extensions);
|
||||
}
|
||||
|
||||
if (!regions_to_relayer.empty () && !from_undo) {
|
||||
relayer (regions_to_relayer);
|
||||
}
|
||||
|
||||
if (pending_layering) {
|
||||
LayeringChanged (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
clear_pending ();
|
||||
|
||||
in_flush = false;
|
||||
@ -686,6 +665,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
}
|
||||
|
||||
if (itimes >= 1) {
|
||||
region->set_pending_layer (DBL_MAX);
|
||||
add_region_internal (region, pos);
|
||||
pos += region->length();
|
||||
--itimes;
|
||||
@ -698,6 +678,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
for (int i = 0; i < itimes; ++i) {
|
||||
boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
|
||||
copy->set_pending_layer (DBL_MAX);
|
||||
add_region_internal (copy, pos);
|
||||
pos += region->length();
|
||||
}
|
||||
@ -718,6 +699,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::layer, region->layer());
|
||||
|
||||
boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
|
||||
sub->set_pending_layer (DBL_MAX);
|
||||
add_region_internal (sub, pos);
|
||||
}
|
||||
}
|
||||
@ -758,6 +740,11 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
possibly_splice_unlocked (position, region->length(), region);
|
||||
|
||||
if (!holding_state ()) {
|
||||
/* layers get assigned from XML state, and are not reset during undo/redo */
|
||||
relayer ();
|
||||
}
|
||||
|
||||
/* we need to notify the existence of new region before checking dependents. Ick. */
|
||||
|
||||
notify_region_added (region);
|
||||
@ -780,6 +767,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
_splicing = true;
|
||||
|
||||
remove_region_internal (old);
|
||||
newr->set_pending_layer (newr->layer ());
|
||||
add_region_internal (newr, pos);
|
||||
|
||||
_splicing = old_sp;
|
||||
@ -817,6 +805,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
possibly_splice_unlocked (pos, -distance);
|
||||
|
||||
if (!holding_state ()) {
|
||||
relayer ();
|
||||
remove_dependents (region);
|
||||
}
|
||||
|
||||
@ -873,16 +862,12 @@ Playlist::flush_notifications (bool from_undo)
|
||||
* start and end if cutting == true. Regions that lie entirely within start and end are always
|
||||
* removed.
|
||||
*/
|
||||
|
||||
void
|
||||
Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist)
|
||||
{
|
||||
RegionList new_regions;
|
||||
|
||||
/* Don't relayer regions that are created during this operation; leave them
|
||||
on the same region as the original.
|
||||
*/
|
||||
suspend_relayer ();
|
||||
|
||||
{
|
||||
RegionLock rlock (this);
|
||||
|
||||
@ -962,6 +947,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, pos3 - pos2);
|
||||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::layer, current->layer ());
|
||||
plist.add (Properties::layering_index, current->layering_index ());
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::left_of_split, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
@ -981,6 +967,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, pos4 - pos3);
|
||||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::layer, current->layer ());
|
||||
plist.add (Properties::layering_index, current->layering_index ());
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
|
||||
@ -1019,6 +1006,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, pos4 - pos2);
|
||||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::layer, current->layer ());
|
||||
plist.add (Properties::layering_index, current->layering_index ());
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::left_of_split, true);
|
||||
|
||||
@ -1062,6 +1050,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, pos3 - pos1);
|
||||
plist.add (Properties::name, new_name);
|
||||
plist.add (Properties::layer, current->layer ());
|
||||
plist.add (Properties::layering_index, current->layering_index ());
|
||||
plist.add (Properties::automatic, true);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
|
||||
@ -1108,8 +1097,6 @@ Playlist::flush_notifications (bool from_undo)
|
||||
for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
|
||||
check_dependents (*i, false);
|
||||
}
|
||||
|
||||
resume_relayer ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Playlist>
|
||||
@ -1210,7 +1197,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
int itimes = (int) floor (times);
|
||||
framepos_t pos = position;
|
||||
framecnt_t const shift = other->_get_extent().second;
|
||||
layer_t top_layer = regions.size();
|
||||
layer_t top = top_layer ();
|
||||
|
||||
while (itimes--) {
|
||||
for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
|
||||
@ -1220,7 +1207,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
the ordering they had in the original playlist.
|
||||
*/
|
||||
|
||||
copy_of_region->set_layer (copy_of_region->layer() + top_layer);
|
||||
copy_of_region->set_pending_layer (copy_of_region->layer() + top);
|
||||
add_region_internal (copy_of_region, (*i)->position() + pos);
|
||||
}
|
||||
pos += shift;
|
||||
@ -1242,6 +1229,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
while (itimes--) {
|
||||
boost::shared_ptr<Region> copy = RegionFactory::create (region, true);
|
||||
copy->set_pending_layer (DBL_MAX);
|
||||
add_region_internal (copy, pos);
|
||||
pos += region->length();
|
||||
}
|
||||
@ -1259,6 +1247,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::name, name);
|
||||
|
||||
boost::shared_ptr<Region> sub = RegionFactory::create (region, plist);
|
||||
sub->set_pending_layer (DBL_MAX);
|
||||
add_region_internal (sub, pos);
|
||||
}
|
||||
}
|
||||
@ -1360,6 +1349,8 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, before);
|
||||
plist.add (Properties::name, before_name);
|
||||
plist.add (Properties::left_of_split, true);
|
||||
plist.add (Properties::layering_index, region->layering_index ());
|
||||
plist.add (Properties::layer, region->layer ());
|
||||
|
||||
/* note: we must use the version of ::create with an offset here,
|
||||
since it supplies that offset to the Region constructor, which
|
||||
@ -1377,6 +1368,8 @@ Playlist::flush_notifications (bool from_undo)
|
||||
plist.add (Properties::length, after);
|
||||
plist.add (Properties::name, after_name);
|
||||
plist.add (Properties::right_of_split, true);
|
||||
plist.add (Properties::layering_index, region->layering_index ());
|
||||
plist.add (Properties::layer, region->layer ());
|
||||
|
||||
/* same note as above */
|
||||
right = RegionFactory::create (region, before, plist);
|
||||
@ -1470,8 +1463,6 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
if (what_changed.contains (Properties::position)) {
|
||||
|
||||
timestamp_layer_op (LayerOpBoundsChange, region);
|
||||
|
||||
/* remove it from the list then add it back in
|
||||
the right place again.
|
||||
*/
|
||||
@ -1512,7 +1503,7 @@ Playlist::flush_notifications (bool from_undo)
|
||||
pending_bounds.push_back (region);
|
||||
} else {
|
||||
notify_contents_changed ();
|
||||
relayer (region);
|
||||
relayer ();
|
||||
check_dependents (region, false);
|
||||
}
|
||||
}
|
||||
@ -1572,9 +1563,9 @@ Playlist::flush_notifications (bool from_undo)
|
||||
notify_region_start_trimmed (region);
|
||||
}
|
||||
|
||||
if (what_changed.contains (Properties::layer)) {
|
||||
notify_layering_changed ();
|
||||
}
|
||||
/* don't notify about layer changes, since we are the only object that can initiate
|
||||
them, and we notify in ::relayer()
|
||||
*/
|
||||
|
||||
if (what_changed.contains (our_interests)) {
|
||||
save = true;
|
||||
@ -2134,7 +2125,6 @@ Playlist::flush_notifications (bool from_undo)
|
||||
return -1;
|
||||
}
|
||||
|
||||
suspend_relayer ();
|
||||
freeze ();
|
||||
|
||||
plist = node.properties();
|
||||
@ -2217,7 +2207,6 @@ Playlist::flush_notifications (bool from_undo)
|
||||
|
||||
thaw ();
|
||||
notify_contents_changed ();
|
||||
resume_relayer ();
|
||||
|
||||
in_set_state--;
|
||||
first_set_state = false;
|
||||
@ -2345,277 +2334,189 @@ Playlist::set_edit_mode (EditMode mode)
|
||||
_edit_mode = mode;
|
||||
}
|
||||
|
||||
/** Relayer a region. See the other relayer() methods for commentary. */
|
||||
struct RelayerSort {
|
||||
bool operator () (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
|
||||
return a->layering_index() < b->layering_index();
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Playlist::relayer (boost::shared_ptr<Region> region)
|
||||
Playlist::relayer ()
|
||||
{
|
||||
if (_relayer_suspended) {
|
||||
/* never compute layers when changing state for undo/redo or setting from XML */
|
||||
|
||||
if (in_update || in_set_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegionList r;
|
||||
r.push_back (region);
|
||||
relayer (r);
|
||||
bool changed = false;
|
||||
|
||||
/* Build up a new list of regions on each layer, stored in a set of lists
|
||||
each of which represent some period of time on some layer. The idea
|
||||
is to avoid having to search the entire region list to establish whether
|
||||
each region overlaps another */
|
||||
|
||||
/* how many pieces to divide this playlist's time up into */
|
||||
int const divisions = 512;
|
||||
|
||||
/* find the start and end positions of the regions on this playlist */
|
||||
framepos_t start = INT64_MAX;
|
||||
framepos_t end = 0;
|
||||
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
start = min (start, (*i)->position());
|
||||
end = max (end, (*i)->position() + (*i)->length());
|
||||
}
|
||||
|
||||
Playlist::TemporaryLayers
|
||||
Playlist::compute_temporary_layers (RegionList const & relayer_regions)
|
||||
{
|
||||
TemporaryLayers temporary_layers;
|
||||
OverlapCache cache (this);
|
||||
/* hence the size of each time division */
|
||||
double const division_size = (end - start) / double (divisions);
|
||||
|
||||
for (RegionList::const_iterator i = relayer_regions.begin(); i != relayer_regions.end(); ++i) {
|
||||
vector<vector<RegionList> > layers;
|
||||
layers.push_back (vector<RegionList> (divisions));
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, string_compose ("Compute temporary layer for %1\n", (*i)->name()));
|
||||
RegionList copy = regions.rlist();
|
||||
RegionList pending;
|
||||
|
||||
/* current_overlaps: regions that overlap *i now */
|
||||
RegionList current_overlaps = cache.get ((*i)->bounds ());
|
||||
current_overlaps.remove (*i);
|
||||
/* Remove regions with pending relayers */
|
||||
for (RegionList::iterator i = copy.begin(); i != copy.end(); ) {
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, "Current overlaps:\n");
|
||||
for (RegionList::iterator j = current_overlaps.begin(); j != current_overlaps.end(); ++j) {
|
||||
DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1\n", (*j)->name()));
|
||||
RegionList::iterator j = i;
|
||||
++j;
|
||||
|
||||
if ((*i)->pending_layer()) {
|
||||
pending.push_back (*i);
|
||||
copy.erase (i);
|
||||
}
|
||||
|
||||
/* overlaps_to_preserve: regions that overlap *i now, but which aren't being
|
||||
worked on during this relayer: these will have their relationship with
|
||||
*i preserved.
|
||||
*/
|
||||
RegionList overlaps_to_preserve;
|
||||
|
||||
/* overlaps_to_check: regions that overlap *i now, and must be checked to
|
||||
see if *i is still on the correct layer with respect to them (according
|
||||
to current layering rules).
|
||||
*/
|
||||
RegionList overlaps_to_check;
|
||||
|
||||
if (_session.config.get_relayer_on_all_edits () || (*i)->last_layer_op (LayerOpAdd) > (*i)->last_layer_op (LayerOpBoundsChange)) {
|
||||
/* We're configured to relayer on all edits, or this region has had
|
||||
no edit since it was added to the playlist, so we're relayering
|
||||
the whole lot; in this case there are no `overlaps_to_preserve'.
|
||||
*/
|
||||
overlaps_to_check = current_overlaps;
|
||||
} else {
|
||||
/* We're only relayering new overlaps; find them */
|
||||
RegionList last_overlaps = cache.get ((*i)->last_relayer_bounds ());
|
||||
last_overlaps.remove (*i);
|
||||
for (RegionList::const_iterator j = current_overlaps.begin(); j != current_overlaps.end(); ++j) {
|
||||
if (find (last_overlaps.begin(), last_overlaps.end(), *j) == last_overlaps.end()) {
|
||||
/* This is a new overlap, which must be checked */
|
||||
overlaps_to_check.push_back (*j);
|
||||
} else {
|
||||
/* This is an existing overlap, which must be preserved */
|
||||
overlaps_to_preserve.push_back (*j);
|
||||
}
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
|
||||
if (overlaps_to_check.empty ()) {
|
||||
/* There are no overlaps to check, so just leave everything as it is */
|
||||
continue;
|
||||
}
|
||||
/* Sort the remainder */
|
||||
copy.sort (RelayerSort ());
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, "Overlaps to check:\n");
|
||||
for (RegionList::iterator j = overlaps_to_check.begin(); j != overlaps_to_check.end(); ++j) {
|
||||
DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1\n", (*j)->name()));
|
||||
}
|
||||
|
||||
/* Put *i on our overlaps_to_check_list */
|
||||
overlaps_to_check.push_back (*i);
|
||||
|
||||
/* And sort it according to the current layer model */
|
||||
switch (_session.config.get_layer_model()) {
|
||||
case LaterHigher:
|
||||
overlaps_to_check.sort (RegionSortByPosition ());
|
||||
break;
|
||||
case AddOrBoundsChangeHigher:
|
||||
overlaps_to_check.sort (RegionSortByAddOrBounds ());
|
||||
break;
|
||||
case AddHigher:
|
||||
overlaps_to_check.sort (RegionSortByAdd ());
|
||||
/* Re-insert the pending layers in the right places */
|
||||
for (RegionList::iterator i = pending.begin(); i != pending.end(); ++i) {
|
||||
RegionList::iterator j = copy.begin();
|
||||
while (j != copy.end ()) {
|
||||
if ((*j)->pending_layer().get_value_or ((*j)->layer ()) > (*i)->pending_layer().get ()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now find *i in our overlaps_to_check list; within this list it will be in the
|
||||
right place wrt the current layering rules, so we can work out the layers of the
|
||||
nearest regions below and above.
|
||||
*/
|
||||
double previous_layer = -DBL_MAX;
|
||||
double next_layer = DBL_MAX;
|
||||
RegionList::const_iterator j = overlaps_to_check.begin();
|
||||
while (*j != *i) {
|
||||
previous_layer = temporary_layers.get (*j);
|
||||
++j;
|
||||
}
|
||||
|
||||
/* we must have found *i */
|
||||
assert (j != overlaps_to_check.end ());
|
||||
|
||||
++j;
|
||||
if (j != overlaps_to_check.end ()) {
|
||||
next_layer = temporary_layers.get (*j);
|
||||
copy.insert (j, *i);
|
||||
}
|
||||
|
||||
if (next_layer < previous_layer) {
|
||||
/* If this happens, it means that it's impossible to put *i between overlaps_to_check
|
||||
in a way that satisfies the current layering rule. So we'll punt and put *i
|
||||
above previous_layer.
|
||||
bool had_pending = false;
|
||||
|
||||
for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
|
||||
|
||||
/* reset the pending layer for every region now that we're relayering */
|
||||
if ((*i)->reset_pending_layer ()) {
|
||||
had_pending = true;
|
||||
}
|
||||
|
||||
/* find the time divisions that this region covers; if there are no regions on the list,
|
||||
division_size will equal 0 and in this case we'll just say that
|
||||
start_division = end_division = 0.
|
||||
*/
|
||||
next_layer = DBL_MAX;
|
||||
int start_division = 0;
|
||||
int end_division = 0;
|
||||
|
||||
if (division_size > 0) {
|
||||
start_division = floor ( ((*i)->position() - start) / division_size);
|
||||
end_division = floor ( ((*i)->position() + (*i)->length() - start) / division_size );
|
||||
if (end_division == divisions) {
|
||||
end_division--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know where *i and overlaps_to_preserve should go: between previous_layer and
|
||||
next_layer.
|
||||
assert (divisions == 0 || end_division < divisions);
|
||||
|
||||
/* find the lowest layer that this region can go on */
|
||||
size_t j = layers.size();
|
||||
while (j > 0) {
|
||||
/* try layer j - 1; it can go on if it overlaps no other region
|
||||
that is already on that layer
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, string_compose ("%1 and deps need to go between %2 and %3\n", (*i)->name(), previous_layer, next_layer));
|
||||
|
||||
/* Recurse into overlaps_to_preserve to find dependents */
|
||||
RegionList recursed_overlaps_to_preserve;
|
||||
|
||||
for (RegionList::const_iterator k = overlaps_to_preserve.begin(); k != overlaps_to_preserve.end(); ++k) {
|
||||
recursed_overlaps_to_preserve.push_back (*k);
|
||||
RegionList touched = recursive_regions_touched (*k, cache, *i);
|
||||
for (RegionList::iterator m = touched.begin(); m != touched.end(); ++m) {
|
||||
if (find (recursed_overlaps_to_preserve.begin(), recursed_overlaps_to_preserve.end(), *m) == recursed_overlaps_to_preserve.end()) {
|
||||
recursed_overlaps_to_preserve.push_back (*m);
|
||||
}
|
||||
bool overlap = false;
|
||||
for (int k = start_division; k <= end_division; ++k) {
|
||||
RegionList::iterator l = layers[j-1][k].begin ();
|
||||
while (l != layers[j-1][k].end()) {
|
||||
if ((*l)->overlap_equivalent (*i)) {
|
||||
overlap = true;
|
||||
break;
|
||||
}
|
||||
l++;
|
||||
}
|
||||
|
||||
/* Put *i into the overlaps_to_preserve list */
|
||||
recursed_overlaps_to_preserve.push_back (*i);
|
||||
|
||||
/* Sort it by layer, so that we preserve layering */
|
||||
recursed_overlaps_to_preserve.sort (SortByTemporaryLayer (temporary_layers));
|
||||
|
||||
/* Divide available space up into chunks so that we can relayer everything in that space */
|
||||
double const space = (next_layer - previous_layer) / (recursed_overlaps_to_preserve.size() + 1);
|
||||
|
||||
/* And relayer */
|
||||
int m = 1;
|
||||
for (RegionList::const_iterator k = recursed_overlaps_to_preserve.begin(); k != recursed_overlaps_to_preserve.end(); ++k) {
|
||||
temporary_layers.set (*k, previous_layer + space * m);
|
||||
++m;
|
||||
if (overlap) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return temporary_layers;
|
||||
if (overlap) {
|
||||
/* overlap, so we must use layer j */
|
||||
break;
|
||||
}
|
||||
|
||||
/** Take a list of temporary layer indices and set up the layers of all regions
|
||||
* based on them.
|
||||
*/
|
||||
void
|
||||
Playlist::commit_temporary_layers (TemporaryLayers const & temporary_layers)
|
||||
{
|
||||
/* Sort all the playlist's regions by layer, ascending */
|
||||
RegionList all_regions = regions.rlist ();
|
||||
all_regions.sort (SortByTemporaryLayer (temporary_layers));
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, "Commit layering:\n");
|
||||
|
||||
for (RegionList::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
|
||||
|
||||
/* Go through the regions that we have already layered and hence work
|
||||
out the maximum layer index that is in used at some point during
|
||||
region *i.
|
||||
*/
|
||||
|
||||
layer_t max_layer_here = 0;
|
||||
bool have_overlap = false;
|
||||
for (RegionList::iterator j = all_regions.begin(); j != i; ++j) {
|
||||
if ((*j)->overlap_equivalent (*i)) {
|
||||
max_layer_here = max ((*j)->layer (), max_layer_here);
|
||||
have_overlap = true;
|
||||
}
|
||||
--j;
|
||||
}
|
||||
|
||||
if (have_overlap) {
|
||||
/* *i overlaps something, so put it on the next available layer */
|
||||
(*i)->set_layer (max_layer_here + 1);
|
||||
} else {
|
||||
/* no overlap, so put on the bottom layer */
|
||||
(*i)->set_layer (0);
|
||||
if (j == layers.size()) {
|
||||
/* we need a new layer for this region */
|
||||
layers.push_back (vector<RegionList> (divisions));
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Layering, string_compose ("\t%1 temporary %2 committed %3\n", (*i)->name(), temporary_layers.get (*i), (*i)->layer()));
|
||||
}
|
||||
/* put a reference to this region in each of the divisions that it exists in */
|
||||
for (int k = start_division; k <= end_division; ++k) {
|
||||
layers[j][k].push_back (*i);
|
||||
}
|
||||
|
||||
/** Relayer a list of regions.
|
||||
*
|
||||
* Taking each region R in turn, this method examines the regions O that overlap R in time.
|
||||
* If the session configuration option "relayer-on-all-moves" is false, we reduce O so that
|
||||
* it contains only those regions with which new overlaps have been formed since the last
|
||||
* relayer.
|
||||
*
|
||||
* We then change the layer of R and its indirect overlaps so that R meets the current
|
||||
* Session layer model with respect to O. See doc/layering.
|
||||
*/
|
||||
|
||||
void
|
||||
Playlist::relayer (RegionList const & relayer_regions)
|
||||
{
|
||||
if (_relayer_suspended) {
|
||||
return;
|
||||
if ((*i)->layer() != j) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/* We do this in two parts: first; compute `temporary layer' indices for
|
||||
regions on the playlist. These are (possibly) fractional indices, which
|
||||
are a convenient means of working with things when you want to insert layers
|
||||
between others.
|
||||
*/
|
||||
|
||||
TemporaryLayers temporary_layers = compute_temporary_layers (relayer_regions);
|
||||
|
||||
/* Second, we fix up these temporary layers and `commit' them by writing
|
||||
them to the regions involved.
|
||||
*/
|
||||
|
||||
commit_temporary_layers (temporary_layers);
|
||||
(*i)->set_layer (j);
|
||||
}
|
||||
|
||||
/** Put a region on some fractional layer and sort everything else out around it.
|
||||
* This can be used to force a region into some layering; for example, calling
|
||||
* this method with temporary_layer == -0.5 will put the region at the bottom of
|
||||
* the stack.
|
||||
*/
|
||||
|
||||
void
|
||||
Playlist::relayer (boost::shared_ptr<Region> region, double temporary_layer)
|
||||
{
|
||||
if (_relayer_suspended) {
|
||||
return;
|
||||
if (changed) {
|
||||
notify_layering_changed ();
|
||||
}
|
||||
|
||||
TemporaryLayers t;
|
||||
t.set (region, temporary_layer);
|
||||
commit_temporary_layers (t);
|
||||
if (had_pending) {
|
||||
uint64_t i = 0;
|
||||
for (RegionList::iterator j = copy.begin(); j != copy.end(); ++j) {
|
||||
(*j)->set_layering_index (i++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::raise_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
relayer (region, region->layer() + 1.5);
|
||||
region->set_pending_layer (region->layer() + 1.5);
|
||||
relayer ();
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::lower_region (boost::shared_ptr<Region> region)
|
||||
{
|
||||
relayer (region, region->layer() - 1.5);
|
||||
region->set_pending_layer (region->layer() - 1.5);
|
||||
relayer ();
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
|
||||
{
|
||||
relayer (region, max_layer);
|
||||
region->set_pending_layer (DBL_MAX);
|
||||
relayer ();
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
|
||||
{
|
||||
relayer (region, -0.5);
|
||||
region->set_pending_layer (-0.5);
|
||||
relayer ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2750,24 +2651,9 @@ Playlist::set_frozen (bool yn)
|
||||
_frozen = yn;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::timestamp_layer_op (LayerOp op, boost::shared_ptr<Region> region)
|
||||
{
|
||||
region->set_last_layer_op (op, ++layer_op_counter);
|
||||
}
|
||||
|
||||
|
||||
/** Find the next or previous region after `region' (next if dir > 0, previous otherwise)
|
||||
* and swap its position with `region'.
|
||||
*/
|
||||
void
|
||||
Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
|
||||
{
|
||||
/* As regards layering, the calls we make to set_position() will
|
||||
perform layering as if the regions had been moved, which I think
|
||||
is about right.
|
||||
*/
|
||||
|
||||
bool moved = false;
|
||||
|
||||
if (region->locked()) {
|
||||
@ -2872,9 +2758,13 @@ Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
|
||||
_shuffling = false;
|
||||
|
||||
if (moved) {
|
||||
|
||||
relayer ();
|
||||
check_dependents (region, false);
|
||||
|
||||
notify_contents_changed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3293,145 +3183,16 @@ Playlist::set_orig_track_id (const PBD::ID& id)
|
||||
_orig_track_id = id;
|
||||
}
|
||||
|
||||
/** Set the temporary layer for a region */
|
||||
void
|
||||
Playlist::TemporaryLayers::set (boost::shared_ptr<Region> r, double l)
|
||||
uint64_t
|
||||
Playlist::highest_layering_index () const
|
||||
{
|
||||
_map[r] = l;
|
||||
RegionLock rlock (const_cast<Playlist *> (this));
|
||||
|
||||
uint64_t h = 0;
|
||||
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
h = max (h, (*i)->layering_index ());
|
||||
}
|
||||
|
||||
/** Return the temporary layer for a region, if one has been specified
|
||||
* to this TemporaryLayers object; if not return the region's current
|
||||
* layer.
|
||||
*/
|
||||
double
|
||||
Playlist::TemporaryLayers::get (boost::shared_ptr<Region> r) const
|
||||
{
|
||||
Map::const_iterator i = _map.find (r);
|
||||
if (i != _map.end ()) {
|
||||
return i->second;
|
||||
}
|
||||
|
||||
return double (r->layer ());
|
||||
}
|
||||
|
||||
int const Playlist::OverlapCache::_divisions = 512;
|
||||
|
||||
/** Set up an OverlapCache for a playlist; the cache will only be valid until
|
||||
* the Playlist is changed.
|
||||
*/
|
||||
Playlist::OverlapCache::OverlapCache (Playlist* playlist)
|
||||
: _range (0, 0)
|
||||
{
|
||||
/* Find the start and end positions of the regions on this playlist */
|
||||
_range = Evoral::Range<framepos_t> (max_framepos, 0);
|
||||
RegionList const & rl = playlist->region_list().rlist ();
|
||||
for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
|
||||
Evoral::Range<framepos_t> const b = (*i)->bounds ();
|
||||
_range.from = min (_range.from, b.from);
|
||||
_range.to = max (_range.to, b.to);
|
||||
}
|
||||
|
||||
/* Hence the size of each time divison */
|
||||
_division_size = (_range.to - _range.from) / double (_divisions);
|
||||
|
||||
_cache.resize (_divisions);
|
||||
|
||||
/* Build the cache */
|
||||
for (RegionList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
|
||||
pair<int, int> ind = cache_indices ((*i)->bounds ());
|
||||
for (int j = ind.first; j < ind.second; ++j) {
|
||||
_cache[j].push_back (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param range Range, in frames.
|
||||
* @return From and to cache indices for (to is exclusive).
|
||||
*/
|
||||
pair<int, int>
|
||||
Playlist::OverlapCache::cache_indices (Evoral::Range<framepos_t> range) const
|
||||
{
|
||||
range.from = max (range.from, _range.from);
|
||||
range.to = min (range.to, _range.to);
|
||||
|
||||
pair<int, int> const p = make_pair (
|
||||
floor ((range.from - _range.from) / _division_size),
|
||||
ceil ((range.to - _range.from) / _division_size)
|
||||
);
|
||||
|
||||
assert (p.first >= 0);
|
||||
assert (p.second <= _divisions);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Return the regions that overlap a given range. The returned list
|
||||
* is not guaranteed to be in the same order as the Playlist that it was
|
||||
* generated from.
|
||||
*/
|
||||
Playlist::RegionList
|
||||
Playlist::OverlapCache::get (Evoral::Range<framepos_t> range) const
|
||||
{
|
||||
if (_range.from == max_framepos) {
|
||||
return RegionList ();
|
||||
}
|
||||
|
||||
RegionList r;
|
||||
|
||||
pair<int, int> ind = cache_indices (range);
|
||||
for (int i = ind.first; i < ind.second; ++i) {
|
||||
for (RegionList::const_iterator j = _cache[i].begin(); j != _cache[i].end(); ++j) {
|
||||
if ((*j)->coverage (range.from, range.to) != OverlapNone) {
|
||||
r.push_back (*j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.sort ();
|
||||
r.unique ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::suspend_relayer ()
|
||||
{
|
||||
_relayer_suspended = true;
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::resume_relayer ()
|
||||
{
|
||||
_relayer_suspended = false;
|
||||
}
|
||||
|
||||
/** Examine a region and return regions which overlap it, and also those which overlap those which overlap etc.
|
||||
* @param ignore Optional region which should be treated as if it doesn't exist (ie not returned in the list,
|
||||
* and not recursed into).
|
||||
*/
|
||||
Playlist::RegionList
|
||||
Playlist::recursive_regions_touched (boost::shared_ptr<Region> region, OverlapCache const & cache, boost::shared_ptr<Region> ignore) const
|
||||
{
|
||||
RegionList touched;
|
||||
recursive_regions_touched_sub (region, cache, ignore, touched);
|
||||
|
||||
touched.remove (region);
|
||||
return touched;
|
||||
}
|
||||
|
||||
/** Recursive sub-routine of recursive_regions_touched */
|
||||
void
|
||||
Playlist::recursive_regions_touched_sub (
|
||||
boost::shared_ptr<Region> region, OverlapCache const & cache, boost::shared_ptr<Region> ignore, RegionList & touched
|
||||
) const
|
||||
{
|
||||
RegionList r = cache.get (region->bounds ());
|
||||
for (RegionList::iterator i = r.begin(); i != r.end(); ++i) {
|
||||
if (find (touched.begin(), touched.end(), *i) == touched.end() && *i != ignore) {
|
||||
touched.push_back (*i);
|
||||
recursive_regions_touched_sub (*i, cache, ignore, touched);
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
@ -73,10 +73,7 @@ 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;
|
||||
PBD::PropertyDescriptor<uint64_t> layering_index;
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,14 +128,8 @@ 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));
|
||||
Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n", Properties::layering_index.property_id));
|
||||
}
|
||||
|
||||
void
|
||||
@ -169,10 +160,7 @@ 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);
|
||||
add_property (_layering_index);
|
||||
}
|
||||
|
||||
#define REGION_DEFAULT_STATE(s,l) \
|
||||
@ -199,10 +187,7 @@ Region::register_properties ()
|
||||
, _stretch (Properties::stretch, 1.0) \
|
||||
, _shift (Properties::shift, 1.0) \
|
||||
, _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)
|
||||
, _layering_index (Properties::layering_index, 0)
|
||||
|
||||
#define REGION_COPY_STATE(other) \
|
||||
_sync_marked (Properties::sync_marked, other->_sync_marked) \
|
||||
@ -228,10 +213,7 @@ Region::register_properties ()
|
||||
, _stretch (Properties::stretch, other->_stretch) \
|
||||
, _shift (Properties::shift, other->_shift) \
|
||||
, _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)
|
||||
, _layering_index (Properties::layering_index, other->_layering_index)
|
||||
|
||||
/* derived-from-derived constructor (no sources in constructor) */
|
||||
Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
|
||||
@ -243,6 +225,7 @@ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& n
|
||||
, _first_edit (EditChangesNothing)
|
||||
{
|
||||
register_properties ();
|
||||
|
||||
/* no sources at this point */
|
||||
}
|
||||
|
||||
@ -1134,12 +1117,9 @@ 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&
|
||||
@ -1330,19 +1310,6 @@ Region::send_change (const PropertyChange& what_changed)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Region::set_last_layer_op (LayerOp op, uint64_t when)
|
||||
{
|
||||
switch (op) {
|
||||
case LayerOpAdd:
|
||||
_last_layer_op_add = when;
|
||||
break;
|
||||
case LayerOpBoundsChange:
|
||||
_last_layer_op_bounds_change = when;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
|
||||
{
|
||||
@ -1683,24 +1650,22 @@ Region::post_set (const PropertyChange& pc)
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Region::last_layer_op (LayerOp op) const
|
||||
void
|
||||
Region::set_pending_layer (double l)
|
||||
{
|
||||
switch (op) {
|
||||
case LayerOpAdd:
|
||||
return _last_layer_op_add;
|
||||
case LayerOpBoundsChange:
|
||||
return _last_layer_op_bounds_change;
|
||||
_pending_layer = l;
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Evoral::Range<framepos_t>
|
||||
Region::bounds () const
|
||||
bool
|
||||
Region::reset_pending_layer ()
|
||||
{
|
||||
return Evoral::Range<framepos_t> (_position, _position + _length);
|
||||
bool const had = _pending_layer;
|
||||
_pending_layer = boost::optional<double> ();
|
||||
return had;
|
||||
}
|
||||
|
||||
|
||||
boost::optional<double>
|
||||
Region::pending_layer () const
|
||||
{
|
||||
return _pending_layer;
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ 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
|
||||
|
@ -974,27 +974,7 @@ int
|
||||
Session::load_options (const XMLNode& node)
|
||||
{
|
||||
LocaleGuard lg (X_("POSIX"));
|
||||
|
||||
/* 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);
|
||||
|
||||
config.set_variables (node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
#include "pbd/compose.h"
|
||||
#include "midi++/manager.h"
|
||||
#include "pbd/textreceiver.h"
|
||||
#include "pbd/compose.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/audioengine.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);
|
||||
|
||||
@ -16,28 +15,68 @@ using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
int const PlaylistLayeringTest::num_regions = 6;
|
||||
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;
|
||||
|
||||
void
|
||||
PlaylistLayeringTest::setUp ()
|
||||
{
|
||||
TestNeedingSession::setUp ();
|
||||
string const test_wav_path = "libs/ardour/test/test.wav";
|
||||
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());
|
||||
|
||||
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
|
||||
@ -45,303 +84,45 @@ PlaylistLayeringTest::tearDown ()
|
||||
{
|
||||
_playlist.reset ();
|
||||
_source.reset ();
|
||||
for (int i = 0; i < num_regions; ++i) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_region[i].reset ();
|
||||
}
|
||||
|
||||
delete[] _region;
|
||||
|
||||
TestNeedingSession::tearDown ();
|
||||
AudioEngine::instance()->remove_session ();
|
||||
delete _session;
|
||||
EnumWriter::destroy ();
|
||||
MIDI::Manager::destroy ();
|
||||
AudioEngine::destroy ();
|
||||
}
|
||||
|
||||
void
|
||||
PlaylistLayeringTest::create_short_regions ()
|
||||
PlaylistLayeringTest::create_three_short_regions ()
|
||||
{
|
||||
PropertyList plist;
|
||||
plist.add (Properties::start, 0);
|
||||
plist.add (Properties::length, 100);
|
||||
for (int i = 0; i < num_regions; ++i) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
_region[i] = RegionFactory::create (_source, plist);
|
||||
_region[i]->set_name (string_compose ("%1", char (int ('A') + i)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlaylistLayeringTest::laterHigher_relayerOnAll_Test ()
|
||||
PlaylistLayeringTest::basicsTest ()
|
||||
{
|
||||
_session->config.set_layer_model (LaterHigher);
|
||||
_session->config.set_relayer_on_all_edits (true);
|
||||
create_three_short_regions ();
|
||||
|
||||
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 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::addHigher_relayerOnAll_Test ()
|
||||
{
|
||||
_session->config.set_layer_model (AddHigher);
|
||||
_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);
|
||||
|
||||
/* 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[A]->set_position (5);
|
||||
|
||||
/* 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 ());
|
||||
/* 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 ());
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "test_needing_session.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Session;
|
||||
@ -8,42 +7,23 @@ namespace ARDOUR {
|
||||
class Source;
|
||||
}
|
||||
|
||||
class PlaylistLayeringTest : public TestNeedingSession
|
||||
class PlaylistLayeringTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (PlaylistLayeringTest);
|
||||
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 (basicsTest);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp ();
|
||||
void tearDown ();
|
||||
|
||||
void lastLayerOpTest ();
|
||||
void addHigher_relayerOnAll_Test ();
|
||||
void addOrBoundsHigher_relayerOnAll_Test ();
|
||||
void laterHigher_relayerOnAll_Test ();
|
||||
void addOrBoundsHigher_relayerWhenNecessary_Test ();
|
||||
void recursiveRelayerTest ();
|
||||
void basicsTest ();
|
||||
|
||||
private:
|
||||
void create_short_regions ();
|
||||
|
||||
static int const num_regions;
|
||||
enum {
|
||||
A = 0,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F
|
||||
};
|
||||
void create_three_short_regions ();
|
||||
|
||||
ARDOUR::Session* _session;
|
||||
boost::shared_ptr<ARDOUR::Playlist> _playlist;
|
||||
boost::shared_ptr<ARDOUR::Source> _source;
|
||||
boost::shared_ptr<ARDOUR::Region>* _region;
|
||||
boost::shared_ptr<ARDOUR::Region> _region[16];
|
||||
};
|
||||
|
@ -1,119 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#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;
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
#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 ();
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#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;
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
};
|
@ -431,8 +431,6 @@ 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()
|
||||
|
||||
|
@ -21,8 +21,8 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Of course, nothing in digital audio is ever quite that simple, and so
|
||||
there are some complications:
|
||||
Of course, nothing in digital audio is ever quite that simple, and so of
|
||||
course there are some complications:
|
||||
</para>
|
||||
|
||||
<section id="layers-crossfades">
|
||||
@ -38,14 +38,14 @@
|
||||
<section id="region-opacity">
|
||||
<title> Region Opacity </title>
|
||||
<para>
|
||||
With a nod to image manipulation programs, Ardour allows you to
|
||||
In a perverse 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 be on their own
|
||||
tracks. Occasionally though, this can be a useful trick.
|
||||
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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -55,27 +55,23 @@
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="choice-of-layering">
|
||||
<title>Choice of layering</title>
|
||||
|
||||
<section id="layering-styles">
|
||||
<title> Layering Styles </title>
|
||||
<para>
|
||||
There are two main decisions to be made with regard to how a playlist
|
||||
should be layered:
|
||||
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>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
Given overlapping regions, which order should they be layered in?
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
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:
|
||||
To facilitate these two contradictory desires, Ardour features three
|
||||
different styles for assigning regions to layers.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
@ -84,17 +80,18 @@
|
||||
<term>Most recently added regions are higher</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Regions which are later in time will be on higher layers.
|
||||
Use this style when recording/overdubbing new material. Edits of
|
||||
any kind do not modify the layering.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Most recently added or edited regions are higher</term>
|
||||
<term>Most recently added/moved/trimmed regions are higher</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Regions which were more recently edited or added to the playlist
|
||||
will be on higher layers.
|
||||
Use this style when recording/overdubbing new material, but you
|
||||
want basic edits to cause regions to rise to the top.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -103,26 +100,25 @@
|
||||
<term>Later regions are higher</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Regions which were more recently added to the playlist will be on higher
|
||||
layers.
|
||||
Use this style when rearranging and editing regions.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
<para>
|
||||
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.
|
||||
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&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.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="modifying-layering-by-hand">
|
||||
<title>Modifying Layering Explicitly</title>
|
||||
<title> Modifying Layering By Hand </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
|
||||
|
Loading…
Reference in New Issue
Block a user