Skip to content

Commit 63c35ea

Browse files
committed
* Requires Bitwig 5.3+
* Implemented adaptive scrolling for play position as well as the loop start and length on all devices which provide these functions. * ROTO CONTROL * New: Support for stepped parameters. Since Bitwig cannot provide the option names, they are labelled Option 1 - Option N. * Fixed: Track button states could get inconsisten when tracks were added or removed. * Fixed: Parameter mapping did only work for parameters on the first page (did crash for all others). Regression in 25.0.1.
1 parent 2fb6b82 commit 63c35ea

26 files changed

+324
-123
lines changed

DrivenByMoss-Manual.pdf

5.22 KB
Binary file not shown.

dependency-reduced-pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<groupId>de.mossgrabers</groupId>
55
<artifactId>DrivenByMoss</artifactId>
66
<name>DrivenByMoss</name>
7-
<version>25.0.1</version>
7+
<version>25.0.2</version>
88
<licenses>
99
<license>
1010
<name>LGPL-2.1-or-later</name>
@@ -228,7 +228,7 @@
228228
<dependency>
229229
<groupId>com.bitwig</groupId>
230230
<artifactId>extension-api</artifactId>
231-
<version>19</version>
231+
<version>21</version>
232232
<scope>compile</scope>
233233
</dependency>
234234
</dependencies>

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<artifactId>DrivenByMoss</artifactId>
77
<packaging>jar</packaging>
88
<name>DrivenByMoss</name>
9-
<version>25.0.1</version>
9+
<version>25.0.2</version>
1010
<properties>
1111
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1212
</properties>
@@ -40,7 +40,7 @@
4040
<dependency>
4141
<groupId>com.bitwig</groupId>
4242
<artifactId>extension-api</artifactId>
43-
<version>19</version>
43+
<version>21</version>
4444
</dependency>
4545
<dependency>
4646
<groupId>net.java.dev.jna</groupId>

src/main/java/de/mossgrabers/bitwig/framework/daw/ModelImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public ModelImpl (final ModelSetup modelSetup, final DataSetup dataSetup, final
9494
this.rootTrackGroup = proj.getRootTrackGroup ();
9595
this.project = new ProjectImpl (this.host, this.valueChanger, proj, bwApplication, numParamPages, numParams);
9696

97-
this.transport = new TransportImpl (controllerHost, this.application, this.valueChanger);
97+
this.transport = new TransportImpl (controllerHost, this.application, bwArranger, this.valueChanger);
9898
this.arranger = new ArrangerImpl (bwArranger);
9999
final int numMarkers = modelSetup.getNumMarkers ();
100100
if (numMarkers > 0)

src/main/java/de/mossgrabers/bitwig/framework/daw/TransportImpl.java

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
package de.mossgrabers.bitwig.framework.daw;
66

77
import java.text.DecimalFormat;
8+
import java.util.Map;
9+
import java.util.TreeMap;
810

11+
import com.bitwig.extension.controller.api.Arranger;
912
import com.bitwig.extension.controller.api.BeatTimeFormatter;
1013
import com.bitwig.extension.controller.api.ControllerHost;
14+
import com.bitwig.extension.controller.api.SettableBeatTimeValue;
1115
import com.bitwig.extension.controller.api.SettableEnumValue;
1216
import com.bitwig.extension.controller.api.TimeSignatureValue;
1317
import com.bitwig.extension.controller.api.Transport;
@@ -35,50 +39,73 @@
3539
public class TransportImpl implements ITransport
3640
{
3741
/** No pre-roll. */
38-
private static final String PREROLL_NONE = "none";
42+
private static final String PREROLL_NONE = "none";
3943
/** 1 bar pre-roll. */
40-
private static final String PREROLL_1_BAR = "one_bar";
44+
private static final String PREROLL_1_BAR = "one_bar";
4145
/** 2 bar pre-roll. */
42-
private static final String PREROLL_2_BARS = "two_bars";
46+
private static final String PREROLL_2_BARS = "two_bars";
4347
/** 4 bar pre-Wroll. */
44-
private static final String PREROLL_4_BARS = "four_bars";
48+
private static final String PREROLL_4_BARS = "four_bars";
4549

46-
private static final String ACTION_JUMP_TO_END = "jump_to_end_of_arrangement";
50+
private static final String ACTION_JUMP_TO_END = "jump_to_end_of_arrangement";
4751

48-
private static final AutomationMode [] AUTOMATION_MODES = new AutomationMode []
52+
private static final AutomationMode [] AUTOMATION_MODES = new AutomationMode []
4953
{
5054
AutomationMode.READ,
5155
AutomationMode.LATCH,
5256
AutomationMode.TOUCH,
5357
AutomationMode.WRITE
5458
};
5559

56-
private static final BeatTimeFormatter BEAT_POSITION_FORMATTER = formatAsBeats (1);
57-
private static final BeatTimeFormatter BEAT_LENGTH_FORMATTER = formatAsBeats (0);
60+
private static final BeatTimeFormatter BEAT_POSITION_FORMATTER = formatAsBeats (1);
61+
private static final BeatTimeFormatter BEAT_LENGTH_FORMATTER = formatAsBeats (0);
5862

59-
private final ControllerHost host;
60-
private final IApplication application;
61-
private final IValueChanger valueChanger;
62-
private final Transport transport;
63+
private static final Map<Double, Double> ZOOM_RESOLUTIONS = new TreeMap<> ();
64+
static
65+
{
66+
ZOOM_RESOLUTIONS.put (Double.valueOf (8.8), Double.valueOf (1.0 / 1));
67+
ZOOM_RESOLUTIONS.put (Double.valueOf (27.94), Double.valueOf (1.0 / 4));
68+
ZOOM_RESOLUTIONS.put (Double.valueOf (279.11), Double.valueOf (1.0 / 16));
69+
ZOOM_RESOLUTIONS.put (Double.valueOf (661.61), Double.valueOf (1.0 / 32));
70+
ZOOM_RESOLUTIONS.put (Double.valueOf (1176.20), Double.valueOf (1.0 / 64));
71+
ZOOM_RESOLUTIONS.put (Double.valueOf (2091.03), Double.valueOf (1.0 / 128));
72+
ZOOM_RESOLUTIONS.put (Double.valueOf (4956.52), Double.valueOf (1.0 / 256));
73+
ZOOM_RESOLUTIONS.put (Double.valueOf (8811.59), Double.valueOf (1.0 / 512));
74+
ZOOM_RESOLUTIONS.put (Double.valueOf (20886.75), Double.valueOf (1.0 / 1024));
75+
ZOOM_RESOLUTIONS.put (Double.valueOf (37132.00), Double.valueOf (1.0 / 2048));
76+
ZOOM_RESOLUTIONS.put (Double.valueOf (66012.45), Double.valueOf (1.0 / 4096));
77+
ZOOM_RESOLUTIONS.put (Double.valueOf (156473.96), Double.valueOf (1.0 / 8192));
78+
ZOOM_RESOLUTIONS.put (Double.valueOf (278175.93), Double.valueOf (1.0 / 16384));
79+
ZOOM_RESOLUTIONS.put (Double.valueOf (600000), Double.valueOf (1.0 / 32768));
80+
ZOOM_RESOLUTIONS.put (Double.valueOf (800000), Double.valueOf (1.0 / 65536));
81+
}
6382

64-
private final IParameter crossfadeParameter;
65-
private final IParameter metronomeVolumeParameter;
66-
private final IParameter automationModeParameter;
83+
private final ControllerHost host;
84+
private final IApplication application;
85+
private final IValueChanger valueChanger;
86+
private final Transport transport;
87+
88+
private final IParameter crossfadeParameter;
89+
private final IParameter metronomeVolumeParameter;
90+
private final IParameter automationModeParameter;
91+
private final Arranger bwArranger;
6792

6893

6994
/**
7095
* Constructor
7196
*
7297
* @param host The host
7398
* @param application The application
99+
* @param bwArranger The Bitwig arranger
74100
* @param valueChanger The value changer
75101
*/
76-
public TransportImpl (final ControllerHost host, final IApplication application, final IValueChanger valueChanger)
102+
public TransportImpl (final ControllerHost host, final IApplication application, final Arranger bwArranger, final IValueChanger valueChanger)
77103
{
78104
this.host = host;
79105
this.application = application;
80106
this.valueChanger = valueChanger;
81107
this.transport = host.createTransport ();
108+
this.bwArranger = bwArranger;
82109

83110
this.transport.isPlaying ().markInterested ();
84111
this.transport.isArrangerRecordEnabled ().markInterested ();
@@ -103,6 +130,8 @@ public TransportImpl (final ControllerHost host, final IApplication application,
103130
this.transport.defaultLaunchQuantization ().markInterested ();
104131
this.transport.isFillModeActive ().markInterested ();
105132

133+
this.bwArranger.getHorizontalScrollbarModel ().getContentPerPixel ().markInterested ();
134+
106135
this.crossfadeParameter = new ParameterImpl (valueChanger, this.transport.crossfade ());
107136
this.metronomeVolumeParameter = new MetronomeVolumeParameterImpl (valueChanger, this.transport.metronomeVolume ());
108137
this.automationModeParameter = new AutomationModeParameter (valueChanger, this);
@@ -140,6 +169,7 @@ public void enableObservers (final boolean enable)
140169
Util.setIsSubscribed (this.transport.getClipLauncherPostRecordingTimeOffset (), enable);
141170
Util.setIsSubscribed (this.transport.defaultLaunchQuantization (), enable);
142171
Util.setIsSubscribed (this.transport.isFillModeActive (), enable);
172+
Util.setIsSubscribed (this.bwArranger.getHorizontalScrollbarModel ().getContentPerPixel (), enable);
143173

144174
this.crossfadeParameter.enableObservers (enable);
145175
this.metronomeVolumeParameter.enableObservers (enable);
@@ -522,27 +552,16 @@ public double getPosition ()
522552
@Override
523553
public void changePosition (final boolean increase, final boolean slow)
524554
{
525-
final double frac = getTimeFraction (slow);
526-
final double position = this.transport.playStartPosition ().get ();
527-
double newPos = Math.max (0, position + (increase ? frac : -frac));
528-
529-
// Adjust to resolution
530-
final double intPosition = Math.floor (newPos / frac);
531-
newPos = intPosition * frac;
532-
533-
this.setPosition (newPos);
555+
final double resolution = this.getZoomResolution ();
556+
final double fraction = this.calcScrollFraction (resolution, slow);
557+
final double position = Math.round (this.transport.playStartPosition ().get () / fraction) * fraction;
558+
this.setPosition (increase ? position + fraction : Math.max (position - fraction, 0.0));
534559
}
535560

536561

537-
/**
538-
* Get the fraction to use for time changes.
539-
*
540-
* @param slow Slow change if true otherwise fast
541-
* @return The fraction to change
542-
*/
543-
private static double getTimeFraction (final boolean slow)
562+
private double calcScrollFraction (final double resolution, final boolean slow)
544563
{
545-
return slow ? TransportConstants.INC_FRACTION_TIME_SLOW : TransportConstants.INC_FRACTION_TIME;
564+
return slow ? resolution : resolution * this.getQuartersPerMeasure () * 4;
546565
}
547566

548567

@@ -558,8 +577,11 @@ public String getLoopStartBeatText ()
558577
@Override
559578
public void changeLoopStart (final boolean increase, final boolean slow)
560579
{
561-
final double frac = getTimeFraction (slow);
562-
this.transport.arrangerLoopStart ().inc (increase ? frac : -frac);
580+
final double resolution = this.getZoomResolution ();
581+
final double fraction = this.calcScrollFraction (resolution, slow);
582+
final SettableBeatTimeValue arrangerLoopStart = this.transport.arrangerLoopStart ();
583+
final double position = Math.round (arrangerLoopStart.get () / fraction) * fraction;
584+
arrangerLoopStart.set (increase ? position + fraction : Math.max (position - fraction, 0.0));
563585
}
564586

565587

@@ -603,8 +625,11 @@ public String getLoopLengthBeatText ()
603625
@Override
604626
public void changeLoopLength (final boolean increase, final boolean slow)
605627
{
606-
final double frac = getTimeFraction (slow);
607-
this.transport.arrangerLoopDuration ().inc (increase ? frac : -frac);
628+
final double resolution = this.getZoomResolution ();
629+
final double fraction = this.calcScrollFraction (resolution, slow);
630+
final SettableBeatTimeValue arrangerLoopDuration = this.transport.arrangerLoopDuration ();
631+
final double position = Math.round (arrangerLoopDuration.get () / fraction) * fraction;
632+
arrangerLoopDuration.set (increase ? position + fraction : Math.max (position - fraction, 0.0));
608633
}
609634

610635

@@ -924,4 +949,18 @@ private static BeatTimeFormatter formatAsBeats (final int offset)
924949
return StringUtils.formatMeasuresLong (quartersPerMeasure, beatTime, offset, true);
925950
};
926951
}
952+
953+
954+
private double getZoomResolution ()
955+
{
956+
final double contentPerPixel = this.bwArranger.getHorizontalScrollbarModel ().getContentPerPixel ().get ();
957+
final double inverseContentPerPixel = 1 / contentPerPixel;
958+
959+
for (final Map.Entry<Double, Double> entry: ZOOM_RESOLUTIONS.entrySet ())
960+
{
961+
if (inverseContentPerPixel < entry.getKey ().doubleValue ())
962+
return entry.getValue ().doubleValue ();
963+
}
964+
return 800000.0;
965+
}
927966
}

src/main/java/de/mossgrabers/bitwig/framework/daw/data/CrossfadeParameter.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
package de.mossgrabers.bitwig.framework.daw.data;
66

7+
import com.bitwig.extension.controller.api.Track;
8+
79
import de.mossgrabers.framework.controller.valuechanger.IValueChanger;
810
import de.mossgrabers.framework.parameter.AbstractParameterImpl;
911

10-
import com.bitwig.extension.controller.api.Track;
11-
1212

1313
/**
1414
* A parameter encapsulating the tracks cross-fade setting.
@@ -32,8 +32,8 @@ private enum CrossfadeSetting
3232
* Constructor.
3333
*
3434
* @param valueChanger The value changer
35-
* @param track The track which crossfade setting to edit
36-
* @param index The index of the crossfade parameter
35+
* @param track The track which cross-fade setting to edit
36+
* @param index The index of the cross-fade parameter
3737
*/
3838
public CrossfadeParameter (final IValueChanger valueChanger, final Track track, final int index)
3939
{
@@ -150,4 +150,12 @@ public void resetValue ()
150150
{
151151
this.setNormalizedValue (0.5);
152152
}
153+
154+
155+
/** {@inheritDoc} */
156+
@Override
157+
public int getNumberOfSteps ()
158+
{
159+
return 3;
160+
}
153161
}

src/main/java/de/mossgrabers/bitwig/framework/daw/data/MuteParameterImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,12 @@ public void setIndication (final boolean enable)
160160
{
161161
// Not supported
162162
}
163+
164+
165+
/** {@inheritDoc} */
166+
@Override
167+
public int getNumberOfSteps ()
168+
{
169+
return 2;
170+
}
163171
}

src/main/java/de/mossgrabers/bitwig/framework/daw/data/RangedValueImpl.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
package de.mossgrabers.bitwig.framework.daw.data;
66

7-
import de.mossgrabers.framework.controller.valuechanger.IValueChanger;
8-
import de.mossgrabers.framework.parameter.AbstractParameterImpl;
9-
107
import com.bitwig.extension.controller.api.DoubleValue;
118
import com.bitwig.extension.controller.api.SettableRangedValue;
129
import com.bitwig.extension.controller.api.StringValue;
1310

11+
import de.mossgrabers.framework.controller.valuechanger.IValueChanger;
12+
import de.mossgrabers.framework.parameter.AbstractParameterImpl;
13+
1414

1515
/**
1616
* Encapsulates the data of a ranged value.
@@ -58,6 +58,7 @@ public RangedValueImpl (final String name, final IValueChanger valueChanger, fin
5858
this.rangedValue = rangedValue;
5959
this.rangedValue.markInterested ();
6060
this.rangedValue.displayedValue ().markInterested ();
61+
this.rangedValue.discreteValueCount ().markInterested ();
6162
}
6263

6364

@@ -67,6 +68,7 @@ public void enableObservers (final boolean enable)
6768
{
6869
Util.setIsSubscribed (this.rangedValue, enable);
6970
Util.setIsSubscribed (this.rangedValue.displayedValue (), enable);
71+
Util.setIsSubscribed (this.rangedValue.discreteValueCount (), enable);
7072
}
7173

7274

@@ -159,6 +161,14 @@ public void resetValue ()
159161
}
160162

161163

164+
/** {@inheritDoc} */
165+
@Override
166+
public int getNumberOfSteps ()
167+
{
168+
return this.rangedValue.discreteValueCount ().get ();
169+
}
170+
171+
162172
/**
163173
* Workaround for new hardware API to still be able to receive values via the old interface.
164174
*

src/main/java/de/mossgrabers/bitwig/framework/daw/data/SoloParameterImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,12 @@ public void setIndication (final boolean enable)
160160
{
161161
// Not supported
162162
}
163+
164+
165+
/** {@inheritDoc} */
166+
@Override
167+
public int getNumberOfSteps ()
168+
{
169+
return 2;
170+
}
163171
}

src/main/java/de/mossgrabers/bitwig/framework/daw/data/bank/AbstractTrackBankImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private void handleBankSelection (final int index)
147147
{
148148
final boolean isSelected = index == i;
149149
final ITrack item = this.getItem (i);
150-
if (item instanceof AbstractItemImpl itemImpl && itemImpl.getRawSelectionState () != isSelected)
150+
if (item instanceof final AbstractItemImpl itemImpl && itemImpl.getRawSelectionState () != isSelected)
151151
{
152152
item.setSelected (isSelected);
153153
this.notifySelectionObservers (i, isSelected);

0 commit comments

Comments
 (0)