3 // allows now to insert breakpoint on double-click by jan trutzschler
5 SCEnvelopeEdit : SCEnvelopeView {
6 var <env, <pointsPerSegment, viewPoints;
7 var <minLevel, <maxLevel, <minTime, <maxTime, totalDurRec, absTimes, numPoints;
9 *viewClass { ^SCEnvelopeView }
11 *new { arg parent, bounds, env, pointsPerSegment=10;
12 ^super.new(parent, bounds).initSCEnvelopeEdit(env, pointsPerSegment)
15 initSCEnvelopeEdit { arg argEnv, argPPS, setMinMax=true;
17 pointsPerSegment = argPPS.asInteger;
19 minLevel = argEnv.levels.minItem;
20 maxLevel = argEnv.levels.maxItem;
21 if(minLevel == maxLevel){ minLevel = 0.0 };
24 maxTime = env.times.sum;
25 totalDurRec = 1/(maxTime - minTime);
27 absTimes = Array.newClear(env.times.size + 1);
29 for(1, env.times.size, { arg i;
30 absTimes[i] = absTimes[i-1] + env.times[i-1];
33 numPoints = (pointsPerSegment * env.times.size) + 1; // add 1 for the last point
34 viewPoints = Array.with(Array.newClear(numPoints), Array.newClear(numPoints));
37 .selectionColor_(Color.clear)
38 .drawLines_(true) // resize broken when no lines drawn
41 this.mouseDownAction_{|view, x, y, modifiers, buttonNumber, clickCount|
42 this.defaultMauseDownAction(x, y, modifiers, buttonNumber, clickCount);
44 this.action = { arg view;
45 var bp, bpm1, bpp1, bpLevel, timePos;
47 // if it's a breakpoint
48 if((view.index % pointsPerSegment) == 0, {
49 bp = view.index.div(pointsPerSegment);
53 bpLevel = view.currentvalue.linlin(0.0, 1.0, minLevel, maxLevel);
54 env.levels[bp] = bpLevel;
56 timePos = view.value[0][view.index].linlin(0.0, 1.0, minTime, maxTime);
60 if( timePos <= absTimes[bpp1], {
61 env.times[bp] = absTimes[bpp1] - timePos;
62 absTimes[bp] = timePos;
63 },{ // going past right break point
65 absTimes[bp] = absTimes[bpp1];
67 this.updateSegment(bp);
69 },{ if(bp == env.times.size, {
70 if( timePos >= absTimes[bpm1], {
71 env.times[bpm1] = timePos - absTimes[bpm1];
72 absTimes[bp] = timePos;
73 },{ // going past left break point
75 absTimes[bp] = absTimes[bpm1];
77 this.updateSegment(bpm1);
78 // a middle break point
80 if(timePos > absTimes[bpp1], { // past right break point
81 env.times[bpm1] = absTimes[bp] - absTimes[bpm1];
83 absTimes[bp] = absTimes[bpp1];
84 },{ if(timePos < absTimes[bpm1], { // past left break point
86 env.times[bp] = absTimes[bpp1] - absTimes[bp];
87 absTimes[bp] = absTimes[bpm1];
89 // set left segment dur
90 env.times[bpm1] = timePos - absTimes[bpm1];
92 // set right segment dur
93 env.times[bp] = absTimes[bpp1] - timePos;
95 absTimes[bp] = timePos;
97 this.updateSegment(bpm1);
98 this.updateSegment(bp);
99 if((timePos <= absTimes[bpp1]) && (timePos >= absTimes[bpm1]), {
112 numPoints.do({ arg i;
114 if((i%pointsPerSegment) == 0, {
115 this.setThumbSize(i, 6);
117 // color code breakpoints
118 if(i.div(pointsPerSegment) == env.releaseNode, {
119 this.setFillColor(i, Color.red(0.7));
121 if(i.div(pointsPerSegment) == env.loopNode, {
122 this.setFillColor(i, Color.green(0.7));
124 this.setFillColor(i, Color.blue(0.7));
128 // Other points should be hidden.
129 },{ this.setThumbSize(i, 0) });
135 this.value = viewPoints;
140 this.value = viewPoints;
144 env.times.size.do({ arg i;
145 this.updateSegment(i);
149 // updates segment values in viewPoints array
150 updateSegment { arg segNum;
151 var time, slope, index1, index2, timeOffset;
153 // update envelope cache
154 // this.debug(env.levels === env.levels);
155 env.times = env.times;
156 // env.levels = env.levels;
157 // env.curves = env.curves;
159 segNum = segNum.asInteger;
161 time = absTimes[segNum];
162 timeOffset = absTimes[0];
164 slope = env.times[segNum] / pointsPerSegment;
166 index1 = pointsPerSegment * segNum;
167 index2 = index1 + pointsPerSegment - 1;
169 for(index1, index2, { arg i;
170 viewPoints[0][i] = time.linlin(minTime, maxTime, 0.0, 1.0);
171 viewPoints[1][i] = env[time - timeOffset].linlin(minLevel, maxLevel, 0.0, 1.0);
175 // draw break point at right level
177 viewPoints[1][index1] = env.levels[segNum].linlin(minLevel, maxLevel, 0.0, 1.0);
180 // the last segment has an extra point at the end
181 if(segNum == (env.times.size-1), {
183 viewPoints[0][index2] = time.linlin(minTime, maxTime, 0.0, 1.0);
184 viewPoints[1][index2] = env.levels.last.linlin(minLevel, maxLevel, 0.0, 1.0);
188 minLevel_ { arg level;
193 maxLevel_ { arg level;
210 defaultMauseDownAction{|x, y, modifiers, buttonNumber, clickCount|
211 var level, time, tbounds;
212 tbounds = this.bounds;
213 level = y.linlin(tbounds.top, tbounds.top+tbounds.height, maxLevel, minLevel);
214 time = x.linlin(tbounds.left, tbounds.left+tbounds.width, minTime, maxTime);
215 // this.debug([time, level]);
218 this.insertAtTime(time, level);
223 this.initSCEnvelopeEdit(e, pointsPerSegment);
226 addBreakPoint{|level|
228 tenv = env.addBreakPoint(level, 0);
229 this.initSCEnvelopeEdit(tenv, pointsPerSegment, false);
231 insertAtTime{|time, level|
233 tenv = env.insertAtTime(time, level);
234 this.initSCEnvelopeEdit(tenv, pointsPerSegment, false);
237 env = nil; pointsPerSegment=10; viewPoints=0;
238 minLevel = maxLevel = minTime = maxTime = totalDurRec = absTimes = numPoints = 0;
239 viewPoints = [[],[]];
243 *paletteExample { arg parent, bounds;
245 v = this.new(parent, bounds, Env.perc);