├── image.png
├── .vscode
├── settings.json
└── launch.json
├── src
├── main
│ ├── resources
│ │ └── META-INF
│ │ │ └── services
│ │ │ └── com.bitwig.extension.ExtensionDefinition
│ └── java
│ │ └── com
│ │ └── centomila
│ │ ├── customPresetsTxt
│ │ ├── Macros
│ │ │ ├── Demo
│ │ │ │ ├── 1-Demo.txt
│ │ │ │ ├── 2-Demo.txt
│ │ │ │ ├── 6-Demo.txt
│ │ │ │ ├── 3-Demo.txt
│ │ │ │ ├── 5-Demo.txt
│ │ │ │ └── 4-Demo.txt
│ │ │ ├── BitX
│ │ │ │ ├── BitX Bpm.txt
│ │ │ │ ├── BitX LDR.txt
│ │ │ │ ├── BitX LIR.txt
│ │ │ │ ├── BitX SMW.txt
│ │ │ │ ├── BitX STS.txt
│ │ │ │ ├── BitX SNF.txt
│ │ │ │ ├── BitX SPN.txt
│ │ │ │ ├── BitX OSC.txt
│ │ │ │ ├── BitX SCF.txt
│ │ │ │ ├── BitX SNT.txt
│ │ │ │ └── BitX ALL.txt
│ │ │ ├── Arrangement
│ │ │ │ ├── Arrangement - Delete All Cue Markers.txt
│ │ │ │ ├── Arrangement - Melodic Techno.txt
│ │ │ │ ├── Arrangement - House.txt
│ │ │ │ ├── Arrangement - Pop.txt
│ │ │ │ ├── Arrangement - Rock.txt
│ │ │ │ ├── Arrangement - Minimal Techno Extended Mix.txt
│ │ │ │ ├── Arrangement - Melodic Techno Original Mix.txt
│ │ │ │ ├── Arrangement - Raw Deep Techno Extended Mix.txt
│ │ │ │ ├── Arrangement - Tech House Extended Mix.txt
│ │ │ │ └── Arrangement - Hypnotic Techno Extended Mix.txt
│ │ │ ├── Samples
│ │ │ │ ├── Arranger Loop Export.txt
│ │ │ │ ├── Check Arm Status.txt
│ │ │ │ ├── Step Set Loop.txt
│ │ │ │ ├── Insert VST3.txt
│ │ │ │ ├── Rename Loop.txt
│ │ │ │ ├── Get Functions and Vars.txt
│ │ │ │ └── Rainbow.txt
│ │ │ ├── BIP and Reverse.txt
│ │ │ ├── Color Tracks in Group.txt
│ │ │ └── Create 8 Tracks.txt
│ │ └── Custom Presets
│ │ │ ├── Kick_Half_Note.txt
│ │ │ ├── Kick_1_and_3.txt
│ │ │ ├── Kick_Triplet_Feel.txt
│ │ │ ├── Kick_Dotted_8th.txt
│ │ │ ├── Kick_Off-Beats.txt
│ │ │ ├── Snare_Half-Time.txt
│ │ │ ├── Snare_Only_on_Beat_2.txt
│ │ │ ├── HiHat_8th_Notes.txt
│ │ │ ├── HiHat_Closed_8th_Dotted.txt
│ │ │ ├── HiHat_Quarter_Notes.txt
│ │ │ ├── Open_HiHat_Quarter.txt
│ │ │ ├── Snare_Backbeat_2_and_4.txt
│ │ │ ├── HiHat_Off-Beat_8ths.txt
│ │ │ ├── HiHat_Shuffle.txt
│ │ │ ├── Kick_Four_on_the_Floor.txt
│ │ │ ├── Kick_Syncopated.txt
│ │ │ ├── Open_HiHat_Off_Beats.txt
│ │ │ ├── HiHat_16th_Notes.txt
│ │ │ ├── Snare_16th_Ghost_Notes.txt
│ │ │ ├── Kick_Driving_8th_Notes.txt
│ │ │ ├── HiHat_Closed_Triplet_Basic.txt
│ │ │ ├── HiHat_Closed_Triplet_Quarter.txt
│ │ │ ├── Snare_16th_Machine_Gun.txt
│ │ │ ├── HiHat_Closed_Eighth_Notes_8Step.txt
│ │ │ ├── HiHat_Closed_Eighth_Accents.txt
│ │ │ ├── HiHat_Closed_Eighths_Crescendo.txt
│ │ │ ├── HiHat_Closed_Triplet_Shuffle.txt
│ │ │ ├── HiHat_Closed_Triplet_Accented.txt
│ │ │ ├── Open_HiHat_Two_Four.txt
│ │ │ └── HiHat_32nd_Notes.txt
│ │ ├── utils
│ │ ├── commands
│ │ │ ├── utility
│ │ │ │ ├── package-info.java
│ │ │ │ ├── WaitCommand.java
│ │ │ │ ├── ListCommandsCommand.java
│ │ │ │ ├── PrintActionsCommand.java
│ │ │ │ ├── MacroCommand.java
│ │ │ │ ├── MessageCommand.java
│ │ │ │ └── ConsoleCommand.java
│ │ │ ├── clip
│ │ │ │ ├── package-info.java
│ │ │ │ ├── ClipLoopOnCommand.java
│ │ │ │ ├── ClipLoopOffCommand.java
│ │ │ │ ├── ClipRenameCommand.java
│ │ │ │ ├── ClipOffsetCommand.java
│ │ │ │ ├── ClipAccentCommand.java
│ │ │ │ ├── ClipColorCommand.java
│ │ │ │ ├── ClipDuplicateCommand.java
│ │ │ │ ├── ClipLengthCommand.java
│ │ │ │ ├── ClipDeleteCommand.java
│ │ │ │ ├── ClipSelectCommand.java
│ │ │ │ ├── ClipMoveCommand.java
│ │ │ │ └── ClipCreateCommand.java
│ │ │ ├── device
│ │ │ │ ├── package-info.java
│ │ │ │ ├── InsertDeviceCommand.java
│ │ │ │ ├── InsertVST3Command.java
│ │ │ │ └── InsertFileCommand.java
│ │ │ ├── drum
│ │ │ │ ├── package-info.java
│ │ │ │ ├── SelectDrumPadCommand.java
│ │ │ │ ├── InsertFileInDrumPadCommand.java
│ │ │ │ ├── InsertVST3InDrumPadCommand.java
│ │ │ │ ├── CreateDrumPadCommand.java
│ │ │ │ └── InsertBitwigDeviceInDrumPadCommand.java
│ │ │ ├── project
│ │ │ │ ├── package-info.java
│ │ │ │ └── ProjectNameCommand.java
│ │ │ ├── track
│ │ │ │ ├── package-info.java
│ │ │ │ ├── TrackNextCommand.java
│ │ │ │ ├── TrackPrevCommand.java
│ │ │ │ ├── TrackDeleteCommand.java
│ │ │ │ ├── TrackRenameCommand.java
│ │ │ │ ├── TrackSelectCommand.java
│ │ │ │ ├── TrackColorCommand.java
│ │ │ │ └── TrackColorAllCommand.java
│ │ │ ├── navigation
│ │ │ │ ├── package-info.java
│ │ │ │ ├── EnterCommand.java
│ │ │ │ ├── EscapeCommand.java
│ │ │ │ ├── UpCommand.java
│ │ │ │ ├── DownCommand.java
│ │ │ │ ├── LeftCommand.java
│ │ │ │ └── RightCommand.java
│ │ │ ├── marker
│ │ │ │ ├── package-info.java
│ │ │ │ ├── DeleteAllCueMarkersCommand.java
│ │ │ │ └── CueMarkerNameCommand.java
│ │ │ ├── step
│ │ │ │ ├── package-info.java
│ │ │ │ ├── StepSelectedIsMutedCommand.java
│ │ │ │ ├── StepSelectedRepeatCountCommand.java
│ │ │ │ ├── StepSelectedIsChanceEnabledCommand.java
│ │ │ │ ├── StepSelectedIsRepeatEnabledCommand.java
│ │ │ │ ├── StepSelectedRepeatCurveCommand.java
│ │ │ │ ├── StepSelectedIsOccurrenceEnabledCommand.java
│ │ │ │ ├── StepSelectedIsRecurrenceEnabledCommand.java
│ │ │ │ ├── StepSelectedRepeatVelocityEndCommand.java
│ │ │ │ ├── StepSelectedRepeatVelocityCurveCommand.java
│ │ │ │ ├── StepSelectedPanCommand.java
│ │ │ │ ├── StepSelectedGainCommand.java
│ │ │ │ ├── StepSelectedTimbreCommand.java
│ │ │ │ ├── StepSelectedChanceCommand.java
│ │ │ │ ├── StepSelectedRecurrenceCommand.java
│ │ │ │ ├── StepSelectedTransposeCommand.java
│ │ │ │ ├── StepSelectedLengthCommand.java
│ │ │ │ ├── StepSelectedOccurrenceCommand.java
│ │ │ │ ├── StepSelectedPressureCommand.java
│ │ │ │ ├── StepSelectedVelocityCommand.java
│ │ │ │ ├── StepSelectedVelocitySpreadCommand.java
│ │ │ │ ├── StepSelectedReleaseVelocityCommand.java
│ │ │ │ └── StepSetCommand.java
│ │ │ ├── bb
│ │ │ │ ├── package-info.java
│ │ │ │ ├── BBGenerateCommand.java
│ │ │ │ ├── BBPresetCommand.java
│ │ │ │ ├── BBArrangerModeCommand.java
│ │ │ │ ├── BBLauncherModeCommand.java
│ │ │ │ ├── BBClosePanelCommand.java
│ │ │ │ ├── BBPatternRepeatCommand.java
│ │ │ │ ├── BBPostActionAutoResizeCommand.java
│ │ │ │ └── BBToggleLauncherArrangerModeCommand.java
│ │ │ ├── transport
│ │ │ │ ├── package-info.java
│ │ │ │ ├── TimeSignatureCommand.java
│ │ │ │ ├── BpmCommand.java
│ │ │ │ ├── TransportPositionCommand.java
│ │ │ │ ├── ArrangerLoopEndCommand.java
│ │ │ │ └── ArrangerLoopStartCommand.java
│ │ │ ├── CommandFactory.java
│ │ │ └── BaseCommand.java
│ │ ├── PopupUtils.java
│ │ ├── DrumPadUtils.java
│ │ ├── OpenWebUrl.java
│ │ └── ExtensionPath.java
│ │ ├── macro
│ │ ├── state
│ │ │ └── BitwigStateProvider.java
│ │ └── commands
│ │ │ └── MacroCommand.java
│ │ ├── BitwigBuddyExtensionDefinition.java
│ │ ├── EditClipSettings.java
│ │ └── DefaultPatterns.java
└── assembly
│ └── distribution.xml
├── .gitignore
├── .github
└── ISSUE_TEMPLATE
├── LICENSE.md
└── readme.md
/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/centomila/BitwigBuddy-Bitwig-Extension/HEAD/image.png
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "java.configuration.updateBuildConfiguration": "automatic"
3 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/com.bitwig.extension.ExtensionDefinition:
--------------------------------------------------------------------------------
1 | com.centomila.BitwigBuddyExtensionDefinition
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/1-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "1-Demo"
2 | Description: ""
3 | Author: "Centomila"
4 |
5 | Message ("Hello!")
6 | Wait(2000)
7 | Macro ("Demo/2-Demo")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Half_Note.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Half Notes"
2 | DefaultNote: "C1"
3 | Pattern: [100, 80, 100, 80]
4 | StepSize: "1/2"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/2"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX Bpm.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX BPM (Tempo)"
2 | Descritpion: "Change the track tempo (Requires BitX)"
3 | Author: "Centomila"
4 |
5 | Clip Color ("FF595E")
6 | Clip Rename ("()BPM 130")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_1_and_3.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick 1 and 3"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Triplet_Feel.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Triplet Feel 12 Steps"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 0, 0, 80, 0, 0, 0, 100, 0, 0, 0]
4 | StepSize: "1/8"
5 | Subdivisions: "3t"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX LDR.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX LDR (Load Drum Rack)"
2 | Descritpion: "Load a drum rack preset (Requires BitX)"
3 | Author: "Centomila"
4 |
5 | Clip Color ("FF924C")
6 | Clip Rename ("()LDR Electronic Kit")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX LIR.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX LIR (Load Instrument)"
2 | Descritpion: "Load an instrument preset (Requires BitX)"
3 | Author: "Centomila"
4 |
5 | Clip Color ("FFCA3A")
6 | Clip Rename ("()LIR Synth Lead:3")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Dotted_8th.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Dotted 8th Pattern"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 100, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "."
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Off-Beats.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Off-Beats (2 and 4)"
2 | DefaultNote: "C1"
3 | Pattern: [0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Snare_Half-Time.txt:
--------------------------------------------------------------------------------
1 | Name: "Snare Single Hit Half-Time"
2 | DefaultNote: "C#1"
3 | Pattern: [0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Snare_Only_on_Beat_2.txt:
--------------------------------------------------------------------------------
1 | Name: "Snare Only on Beat 2"
2 | DefaultNote: "C#1"
3 | Pattern: [0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing utility command implementations.
3 | * These commands handle general operations like message display, waiting, etc.
4 | */
5 | package com.centomila.utils.commands.utility;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_8th_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed 8th Notes"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_8th_Dotted.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Dotted Eighth"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 0, 80, 0, 0, 80, 0, 0, 80, 0, 0, 80, 0, 0, 80]
4 | StepSize: "1/8"
5 | Subdivisions: "."
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Quarter_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Quarter Notes"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Open_HiHat_Quarter.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Open Quarter Notes"
2 | DefaultNote: "D#1"
3 | Pattern: [80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Snare_Backbeat_2_and_4.txt:
--------------------------------------------------------------------------------
1 | Name: "Snare Backbeat 2 and 4"
2 | DefaultNote: "C#1"
3 | Pattern: [0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Delete All Cue Markers.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement: DELETE ALL CUE MARKERS"
2 | Descritpion: "Delete all cue markers"
3 | Author: "Centomila"
4 |
5 | DeleteAllCueMarkers
6 |
7 | Message ("Macro Finished")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX SMW.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX SMW (Setting Message)"
2 | Descritpion: "Display a message about setting up (Requires BitX)"
3 | Author: "Centomila"
4 |
5 | Clip Color ("52A675")
6 | Clip Rename ("()SMW Setting up drum sounds")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX STS.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX STS (Set Time Signature)"
2 | Descritpion: "Set Time Signature for the track (Requires BitX). Usage: ()STS 4:8"
3 | Author: "Centomila"
4 |
5 | Clip Color ("B5A6C9")
6 | Clip Rename ("()STS 4:8")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Off-Beat_8ths.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Off-Beat 8ths"
2 | DefaultNote: "D1"
3 | Pattern: [0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Shuffle.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Accent on Downbeat"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 40, 0, 80, 0, 40, 0, 80, 0, 40, 0, 80, 0, 40, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Four_on_the_Floor.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Four on the Floor"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Syncopated.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Syncopated (1, & of 2, 3)"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 0, 0, 0, 0, 100, 0, 100, 0, 0, 0, 0, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Open_HiHat_Off_Beats.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Open Off-Beat 8ths"
2 | DefaultNote: "D#1"
3 | Pattern: [0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for clip operations.
3 | * These commands handle clip creation, deletion, and manipulation in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.clip;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/device/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for device operations.
3 | * These commands handle device insertion and manipulation in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.device;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for drum pad operations.
3 | * These commands handle drum pad creation, manipulation, and device insertion.
4 | */
5 | package com.centomila.utils.commands.drum;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_16th_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed 16th Notes"
2 | DefaultNote: "D1"
3 | Pattern: [80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Snare_16th_Ghost_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "Snare 16th Ghost Notes"
2 | DefaultNote: "C#1"
3 | Pattern: [20, 0, 20, 0, 100, 0, 20, 0, 20, 0, 20, 0, 100, 0, 20, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/project/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for project-level operations.
3 | * These commands handle project settings and properties in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.project;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for track operations.
3 | * These commands handle track selection, creation, and manipulation in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.track;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Kick_Driving_8th_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "Kick Driving 8th Notes"
2 | DefaultNote: "C1"
3 | Pattern: [100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for navigation actions.
3 | * These commands handle keyboard navigation and UI movement in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.navigation;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Triplet_Basic.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Triplet Basic 18 Step"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0]
4 | StepSize: "1/8"
5 | Subdivisions: "3t"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Triplet_Quarter.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Triplet Quarter 18 Step"
2 | DefaultNote: "D1"
3 | Pattern: [80, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0]
4 | StepSize: "1/8"
5 | Subdivisions: "3t"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Snare_16th_Machine_Gun.txt:
--------------------------------------------------------------------------------
1 | Name: "Snare 16th Machine Gun"
2 | DefaultNote: "C#1"
3 | Pattern: [80, 100, 80, 100, 80, 100, 80, 100, 80, 100, 80, 100, 80, 100, 80, 100]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Eighth_Notes_8Step.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Eighth Notes"
2 | DefaultNote: "D1"
3 | Pattern: [80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80]
4 | StepSize: "1/8"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/marker/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for cue marker operations.
3 | * These commands handle cue marker creation, deletion, and manipulation in Bitwig Studio.
4 | */
5 | package com.centomila.utils.commands.marker;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Eighth_Accents.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Eighth Accented"
2 | DefaultNote: "D1"
3 | Pattern: [100, 60, 100, 60, 100, 60, 100, 60, 100, 60, 100, 60, 100, 60, 100, 60]
4 | StepSize: "1/8"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Eighths_Crescendo.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Eighth Crescendo"
2 | DefaultNote: "D1"
3 | Pattern: [40, 50, 60, 70, 80, 90, 100, 110, 40, 50, 60, 70, 80, 90, 100, 110]
4 | StepSize: "1/8"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Triplet_Shuffle.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Triplet Alt Velocity 18 Step"
2 | DefaultNote: "D1"
3 | Pattern: [90, 0, 40, 0, 90, 0, 40, 0, 90, 0, 40, 0, 90, 0, 40, 0, 90, 0]
4 | StepSize: "1/8"
5 | Subdivisions: "3t"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | *.class
3 | *.jar
4 | *.war
5 | *.ear
6 | *.zip
7 | *.tar.gz
8 | *.rar
9 | *.7z
10 | *.log
11 | *.iml
12 | *.ipr
13 | *.iws
14 | .settings/
15 | .idea/
16 | .m2/
17 | *.iml
18 | *.ipr
19 | *.iws
20 | *.log
21 | *.ser
22 | *.bak
23 | api/
24 | .vscodecounter/
25 | .semanticgraphs/
26 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_Closed_Triplet_Accented.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed Triplet Accented 18 Step"
2 | DefaultNote: "D1"
3 | Pattern: [80, 20, 60, 20, 80, 20, 60, 20, 80, 20, 60, 20, 80, 20, 60, 20, 80, 20]
4 | StepSize: "1/8"
5 | Subdivisions: "3t"
6 | NoteLength: "1/8"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX SNF.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX SNF (Set Note Filter)"
2 | Descritpion: "Set Note Filter - Change the key range for the note filter device (Requires BitX). Usage: ()SNF D1:E5"
3 | Author: "Centomila"
4 |
5 | Clip Color ("1982C4")
6 | Clip Rename ("()SNF C2:C5")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX SPN.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX SPN (Assign Name)"
2 | Descritpion: "Show a Popup Notification that dissapears after a few seconds (Requires BitX). Usage: ()SPN \"Message\""
3 | Author: "Centomila"
4 |
5 | Clip Color ("6A4C93")
6 | Clip Rename ("()SPN I Love BitX")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX OSC.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX OSC (Send OSC Message)"
2 | Descritpion: "Sends an OSC message (Requires BitX). Usage: ()OSC /address arg1 arg2 ..."
3 | Author: "Centomila"
4 |
5 | Clip Color ("C5CA30")
6 | Clip Rename ("()OSC /example/address 1 "string arg" 3.14")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/Open_HiHat_Two_Four.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Open Two and Four"
2 | DefaultNote: "D#1"
3 | Pattern: [0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0]
4 | StepSize: "1/16"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/16"
7 | Notes: "Use with HiHat Closed Quarter Notes pattern"
8 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX SCF.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX SCF (Scale Function)"
2 | Descritpion: "Set Channel filter - Will get the first channel filter on the track and set the channels (Requires BitX). Usage: ()SCF 1:5:9"
3 | Author: "Centomila"
4 |
5 | Clip Color ("8AC926")
6 | Clip Rename ("()SCF 1:3:5")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Custom Presets/HiHat_32nd_Notes.txt:
--------------------------------------------------------------------------------
1 | Name: "HiHat Closed 32nd Roll"
2 | DefaultNote: "D1"
3 | Pattern: [80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60, 80, 60]
4 | StepSize: "1/32"
5 | Subdivisions: "Straight"
6 | NoteLength: "1/32"
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX SNT.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX SNT (Set Note Transform)"
2 | Descritpion: "Set Note Transpose - Adjusts octave, coarse and fine tuning (Requires BitX). Usage: ()SNT octave:coarse:fine e.g. ()SNT 2:30:-40"
3 | Author: "Centomila"
4 |
5 | Clip Color ("4267AC")
6 | Clip Rename ("()SNT 1:20:-10")
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Arranger Loop Export.txt:
--------------------------------------------------------------------------------
1 | Macro: "Export Loop Selection"
2 | Description: "Set the Arranger Loop position, go to export page and confirm with last used settings."
3 | Author: "Centomila"
4 |
5 | Arranger Loop Start (16.0)
6 | Wait (100)
7 | Arranger Loop End (128.0)
8 | Export Audio
9 | Enter
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for step sequencer operations.
3 | * These commands handle note step manipulation in the Bitwig Studio step sequencer,
4 | * such as setting velocity, length, and other note properties.
5 | */
6 | package com.centomila.utils.commands.step;
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for BeatBuddy-specific operations.
3 | * These commands handle operations specific to the BeatBuddy extension functionality
4 | * such as preset selection, pattern generation, and custom features.
5 | */
6 | package com.centomila.utils.commands.bb;
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package containing command implementations for transport-related actions.
3 | * These commands handle operations related to the transport controls in Bitwig Studio,
4 | * such as playback position, tempo, time signature, and looping.
5 | */
6 | package com.centomila.utils.commands.transport;
7 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Check Arm Status.txt:
--------------------------------------------------------------------------------
1 | Macro: "Check Arm Status"
2 | Description: "Check if tracks are armed for recording and show status messages."
3 | Author: "Centomila"
4 |
5 | for (i = 0 to 7) {
6 |
7 | if (isCurrentTrackArmed()) {
8 | Message("${getCurrentTrackName()} is ARMED for recording!")
9 | }
10 |
11 | if (!isCurrentTrackArmed()) {
12 | Message("${getCurrentTrackName()} IS NOT armed for recording!")
13 | }
14 | Track Next
15 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/EnterCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the Enter key.
8 | */
9 | public class EnterCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().enter();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "java",
9 | "name": "Attach to Bitwig",
10 | "request": "attach",
11 | "hostName": "localhost",
12 | "port": "5005"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/EscapeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the Escape key.
8 | */
9 | public class EscapeCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().escape();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/UpCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the up arrow key.
8 | */
9 | public class UpCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().arrowKeyUp();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/DownCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the down arrow key.
8 | */
9 | public class DownCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().arrowKeyDown();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/LeftCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the left arrow key.
8 | */
9 | public class LeftCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().arrowKeyLeft();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBGenerateCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to generate a BeatBuddy drum pattern preset.
8 | */
9 | public class BBGenerateCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.generateDrumPattern();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/navigation/RightCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.navigation;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to press the right arrow key.
8 | */
9 | public class RightCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getApplication().arrowKeyRight();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Step Set Loop.txt:
--------------------------------------------------------------------------------
1 | Macro: "Test Step Set For Loop"
2 | Description: "This macro tests the 'Step Set' command by setting alternating steps in the currently selected clip using a for loop and math."
3 | Author: "Centomila"
4 |
5 | // Parameters: channel, stepIndex, noteDestination, velocity, duration
6 | for (i = 0 to 7) {
7 | var velocity = ${i} * 10
8 | var stepIndex = ${i}*2
9 | Step Set(0, ${stepIndex}, 60, ${velocity}, 0.25)
10 | Message ("${i}")
11 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipLoopOnCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to enable looping for the selected clip.
8 | */
9 | public class ClipLoopOnCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getLauncherOrArrangerAsClip().isLoopEnabled().set(true);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipLoopOffCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to disable looping for the selected clip.
8 | */
9 | public class ClipLoopOffCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | extension.getLauncherOrArrangerAsClip().isLoopEnabled().set(false);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/2-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "2-Demo"
2 | Description: ""
3 | Author: "Centomila"
4 |
5 | Message ("This is a Bitwig Buddy Macro")
6 | Wait (3000)
7 | Message ("Now I will mess up with this project to show you what I can do")
8 | Wait (3000)
9 | Message ("You have 5 seconds to stop me")
10 | Wait (1000)
11 | Message ("5")
12 | Wait (1000)
13 | Message ("4")
14 | Wait (1000)
15 | Message ("3")
16 | Wait (1000)
17 | Message ("2")
18 | Wait (1000)
19 | Message ("1")
20 | Wait (1000)
21 | BB Close Panel
22 | Macro ("Demo/3-Demo")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BIP and Reverse.txt:
--------------------------------------------------------------------------------
1 | Macro: "Bounce In Place then Reverse"
2 | Description: "Bounce in place the Time Selection and reverse it 1 bar earlier."
3 | Author: "Centomila"
4 |
5 | BB Arranger Mode
6 | BB Close Panel
7 | select_time_selection_tool
8 | bounce_in_place
9 | Wait (500)
10 |
11 | switch_between_event_and_time_selection
12 | select_object_selection_tool
13 | reverse
14 | Wait (100)
15 |
16 | Clip Move (-4)
17 | Wait (100)
18 |
19 | Right
20 | Wait (100)
21 |
22 | Clip Move (-4)
23 | Wait (100)
24 |
25 | Clip Offset (0)
26 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackNextCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.utils.commands.BaseCommand;
4 | import com.centomila.BitwigBuddyExtension;
5 |
6 | /**
7 | * Command to navigate to the next track.
8 | */
9 | public class TrackNextCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] args, BitwigBuddyExtension extension) {
13 | // Logic to navigate to the next track using the provided extension
14 | extension.getCursorTrack().selectNext();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackPrevCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.utils.commands.BaseCommand;
4 | import com.centomila.BitwigBuddyExtension;
5 |
6 | /**
7 | * Command to navigate to the previous track.
8 | */
9 | public class TrackPrevCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] args, BitwigBuddyExtension extension) {
13 | // Logic to navigate to the previous track using the provided extension
14 | extension.getCursorTrack().selectPrevious();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/6-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "6-Demo"
2 | Description: "Final part of the demo sequence with clip creation and selection."
3 | Author: "Centomila"
4 |
5 | switch_between_event_and_time_selection
6 | Right
7 | Down
8 | Track Select (2)
9 | move_time_selection_one_event_earlier
10 | Clip Create (1, 4)
11 | Wait (200)
12 | Clip Select
13 | Message ("Weeeeeeeeeeeeeee!")
14 | Macro ("Samples/Rainbow Clip")
15 | Select All
16 | zoom_to_fit_selection_or_all
17 | Stop Transport
18 | Wait (1000)
19 | Message ("End of demo!")
20 | Wait (2000)
21 | Message ("Bye bye!")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/3-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "3-Demo"
2 | Description: ""
3 | Author: "Centomila"
4 |
5 |
6 | Message ("First, we need some tracks...")
7 | Track Select (1)
8 | Wait (1500)
9 | focus_track_header_area
10 | Wait (500)
11 | Macro ("Create 8 Tracks")
12 | Wait (1500)
13 | Message ("Much better!")
14 | Wait (1500)
15 | Message ("Now let's add some cue markers")
16 | Wait (1500)
17 | Macro ("Arrangement/Arrangement - Melodic Techno Original Mix")
18 | Wait (1500)
19 | Message ("Zoom to Fit the arranger...")
20 | arranger_zoom_to_fit
21 | Wait (3000)
22 | Macro ("Demo/4-Demo")
23 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Color Tracks in Group.txt:
--------------------------------------------------------------------------------
1 | Macro: "Color Tracks in Group"
2 | Description: "Remove the color of all tracks in a group and inherit the color of the group track."
3 | Author: "Centomila"
4 |
5 | // Close the BitwigBuddy Panel
6 | BB Close Panel
7 | // Enter the selected group track
8 | Enter Group
9 |
10 | // Assign color (0) to the group track. 0 means no color
11 | Track Color All (0)
12 | Wait (100)
13 | Track Select (1)
14 |
15 | // Wait 100 ms to ensure the color is applied
16 | Wait (100)
17 |
18 | // Exit the group track
19 | Exit Group
20 |
21 | // Go back to the group track
22 | Track Previous
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBPresetCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.PatternSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to select a BeatBuddy preset.
9 | */
10 | public class BBPresetCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | PatternSettings.setCustomPreset(params[0]);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/project/ProjectNameCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.project;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import static com.centomila.utils.PopupUtils.showPopup;
6 |
7 | /**
8 | * Command to display the current project name.
9 | */
10 | public class ProjectNameCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | extension.getApplication().projectName();
15 | showPopup(extension.getApplication().projectName().toString());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBArrangerModeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.SettableEnumValue;
7 |
8 | /**
9 | * Command to switch to Arranger mode.
10 | */
11 | public class BBArrangerModeCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | ((SettableEnumValue) ModeSelectSettings.toggleLauncherArrangerSetting).set("Arranger");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBLauncherModeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.SettableEnumValue;
7 |
8 | /**
9 | * Command to switch to Launcher mode.
10 | */
11 | public class BBLauncherModeCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | ((SettableEnumValue) ModeSelectSettings.toggleLauncherArrangerSetting).set("Launcher");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipRenameCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to rename the currently selected clip.
8 | */
9 | public class ClipRenameCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | String newName = params[0].trim();
18 | extension.getLauncherOrArrangerAsClip().setName(newName);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Insert VST3.txt:
--------------------------------------------------------------------------------
1 | Macro: "Insert VST3"
2 | Description: "This is just for testing."
3 | Author: "Centomila"
4 |
5 | // Time Signature (3/4)
6 | // Clip Loop On
7 | // Select Next
8 | // Clip Loop Off
9 | // Clip Accent (0.752)
10 | // Insert File (2, "c:\Program Files\Common Files\Native Instruments\Kontakt 8\Content\Tools\Phrases\Library Data\MIDI Files\ZA_Last_Dance_Phrases_E_Ionian_Flat_2\06_Last Dance_E_Phrygian Dom_E_Phrygian Dom.mid")
11 | // Insert File (2, "c:\Users\Bach\AppData\Local\Bitwig Studio\installed-packages\5.0\Bitwig\Bitwig Drum Machines\Dub Techno Beat 2 126bpm.bwclip")
12 |
13 |
14 | Insert VST3 ("Serum 2")
15 | Insert VST3 ("Valhalla Supermassive")
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/5-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "5-Demo"
2 | Description: "Demonstrates Zoom to Selection and Bounce in Place operations."
3 | Author: "Centomila"
4 |
5 | Zoom to Selection
6 | play_from_time_selection
7 | Wait (2000)
8 | Stop Transport
9 |
10 | // Select the first note
11 | move_time_selection_one_event_earlier
12 | extend_time_selection_range_to_next_item
13 | extend_time_selection_range_to_next_item
14 | Wait (100)
15 | Macro ("Bounce In Place then Reverse")
16 | Wait (100)
17 | Left
18 | Play Transport
19 | Wait (2000)
20 | Stop Transport
21 |
22 | Message ("Ops. I left the two initial tracks")
23 |
24 | Track Delete (1)
25 | Track Delete (9)
26 | Wait (100)
27 | Track Select (1)
28 | Wait (1000)
29 | Play Transport
30 | Macro ("Demo/6-Demo")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/WaitCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to wait for a specified duration in milliseconds.
8 | */
9 | public class WaitCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | int waitTime = params.length > 0 ? Integer.parseInt(params[0]) : 50;
14 |
15 | try {
16 | Thread.sleep(waitTime);
17 | } catch (InterruptedException e) {
18 | Thread.currentThread().interrupt();
19 | reportError("Wait interrupted: " + e.getMessage(), extension);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/TimeSignatureCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.transport;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the project time signature.
8 | */
9 | public class TimeSignatureCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | extension.transport.timeSignature().set(params[0].trim());
19 | } catch (Exception e) {
20 | reportError("Invalid time signature format: " + params[0], extension);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/PopupUtils.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils;
2 |
3 | import com.bitwig.extension.controller.api.ControllerHost;
4 |
5 | public class PopupUtils {
6 | private static ControllerHost host;
7 |
8 | /**
9 | * @param controllerHost
10 | */
11 | public static void init(ControllerHost controllerHost) {
12 | host = controllerHost;
13 | }
14 |
15 | /**
16 | * @param message // The message to display
17 | */
18 | public static void showPopup(String message) {
19 | if (host != null) {
20 | host.showPopupNotification(message);
21 | }
22 | }
23 |
24 | // Console message
25 | public static void console(String message) {
26 | if (host != null) {
27 | host.println(message);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/BpmCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.transport;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the BPM (tempo) of the project.
8 | */
9 | public class BpmCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | int bpm = Integer.parseInt(params[0].trim());
19 | extension.transport.tempo().setRaw(bpm);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid BPM value: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBClosePanelCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to close the BeatBuddy panel by using a workaround.
8 | * This command opens the Export Audio panel and then sends an Escape key press
9 | * to force the BeatBuddy panel to close.
10 | */
11 | public class BBClosePanelCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | // Open the Export Audio panel
16 | extension.getApplication().getAction("Export Audio").invoke();
17 |
18 | // Then press the Escape key to close it and force BB panel to close
19 | extension.getApplication().escape();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/TransportPositionCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.transport;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the transport position.
8 | */
9 | public class TransportPositionCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | double position = Double.parseDouble(params[0].trim());
19 | extension.transport.setPosition(position);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid position value: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipOffsetCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the playback start offset of a clip.
8 | */
9 | public class ClipOffsetCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | double offset = Double.parseDouble(params[0].trim());
19 | extension.getLauncherOrArrangerAsClip().getPlayStart().set(offset);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid offset value: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipAccentCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the accent value for the selected clip.
8 | */
9 | public class ClipAccentCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | double accentValue = Double.parseDouble(params[0].trim());
19 | extension.getLauncherOrArrangerAsClip().getAccent().setRaw(accentValue);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid accent value: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Demo/4-Demo.txt:
--------------------------------------------------------------------------------
1 | Macro: "4-Demo"
2 | Description: "Demonstrates track selection, device insertion, and clip creation."
3 | Author: "Centomila"
4 |
5 | Track Select (2)
6 | Insert Device ("Drum Machine")
7 | Wait (300)
8 | Message ("This Drum Machine needs a kick")
9 | BB Close Panel
10 | Drum Pad Insert Device ("C1", "V0 Kick")
11 | Wait (1500)
12 | Message ("Let's create a clip in the Arranger")
13 | BB Arranger Mode
14 | focus_or_toggle_arranger
15 | toggle_clip_launcher
16 | Down
17 | Wait (100)
18 | move_time_selection_one_step_later
19 |
20 | Clip Create (0, 1)
21 | Wait (1200)
22 | switch_between_event_and_time_selection
23 | Message ("We need some notes")
24 | Wait (1500)
25 | Wait (100)
26 | BB Preset ("Kick Four on the Floor")
27 | BB Pattern Repeat (8)
28 | BB Post Action AutoResize ("Off")
29 | BB Generate
30 | Wait (1000)
31 |
32 | Macro ("Demo/5-Demo")
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/ArrangerLoopEndCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.transport;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the end position of the arranger loop.
8 | */
9 | public class ArrangerLoopEndCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | double duration = Double.parseDouble(params[0].trim());
19 | extension.transport.arrangerLoopDuration().set(duration);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid loop duration: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBPatternRepeatCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.PatternSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to set the pattern repeat quantity for BeatBuddy.
9 | */
10 | public class BBPatternRepeatCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | int repeatQty = Integer.parseInt(params[0]);
20 | PatternSettings.setRepeatPattern(repeatQty);
21 | } catch (NumberFormatException e) {
22 | reportError("Invalid repeat quantity: " + params[0], extension);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/transport/ArrangerLoopStartCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.transport;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to set the start position of the arranger loop.
8 | */
9 | public class ArrangerLoopStartCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | double startPos = Double.parseDouble(params[0].trim());
19 | extension.transport.arrangerLoopStart().set(startPos);
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid loop start position: " + params[0], extension);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBPostActionAutoResizeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.PostActionSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to set the auto-resize option for post-pattern-generation.
9 | */
10 | public class BBPostActionAutoResizeCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | String setting = params[0].trim();
19 | if (setting.equals("true") || setting.equals("On")) {
20 | PostActionSettings.setAutoResizeLoopLengthSetting("On");
21 | } else {
22 | PostActionSettings.setAutoResizeLoopLengthSetting("Off");
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipColorCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.api.Color;
6 |
7 | /**
8 | * Command to set the color of the currently selected clip.
9 | */
10 | public class ClipColorCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | String colorStr = params[0].trim();
20 | Color color = Color.fromHex(colorStr);
21 | extension.getLauncherOrArrangerAsClip().color().set(color);
22 | } catch (Exception e) {
23 | reportError("Invalid color format: " + params[0], extension);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/marker/DeleteAllCueMarkersCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.marker;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.controller.api.CueMarker;
6 |
7 | /**
8 | * Command to delete all cue markers in the project.
9 | */
10 | public class DeleteAllCueMarkersCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | // Pass through multiple times to ensure all markers are deleted
15 | for (int pass = 0; pass < 16; pass++) {
16 | for (int i = 0; i < 128; i++) {
17 | CueMarker cueMarker = extension.cueMarkerBank.getItemAt(i);
18 | if (cueMarker.exists().get()) {
19 | cueMarker.deleteObject();
20 | }
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipDuplicateCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to duplicate the currently selected clip.
9 | */
10 | public class ClipDuplicateCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Arranger")) {
15 | extension.application.duplicate();
16 | } else {
17 | extension.getLauncherOrArrangerAsClip().clipLauncherSlot().duplicateClip();
18 | int clipPosition = extension.getLauncherOrArrangerAsClip().clipLauncherSlot().sceneIndex().get();
19 | extension.sceneBank.scrollIntoView(clipPosition);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/BitX/BitX ALL.txt:
--------------------------------------------------------------------------------
1 | Macro: "BitX All"
2 | Descritpion: "Change the track tempo (Requires BitX)"
3 | Author: "Centomila"
4 |
5 | Clip Create (1, 16)
6 | Macro ("BitX/BitX BPM (Tempo)")
7 | Clip Duplicate
8 | Select next item
9 | Macro ("BitX/BitX LDR (Load Drum Rack)")
10 | Select next item
11 | Clip Duplicate
12 | Macro ("BitX/BitX LIR (Load Instrument)")
13 | Select next item
14 | Clip Duplicate
15 | Macro ("BitX/BitX OSC (Send OSC Message)")
16 | Select next item
17 | Clip Duplicate
18 | Macro ("BitX/BitX SCF (Scale Function)")
19 | Select next item
20 | Clip Duplicate
21 | Macro ("BitX/BitX SMW (Setting Message)")
22 | Select next item
23 | Clip Duplicate
24 | Macro ("BitX/BitX SNF (Set Note Filter)")
25 | Select next item
26 | Clip Duplicate
27 | Macro ("BitX/BitX SNT (Set Note Transform)")
28 | Select next item
29 | Clip Duplicate
30 | Macro ("BitX/BitX SPN (Assign Name)")
31 | Select next item
32 | Clip Duplicate
33 | Macro ("BitX/BitX STS (Set Time Signature)")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Rename Loop.txt:
--------------------------------------------------------------------------------
1 | Macro: "Rename Loop Incremental"
2 | Description: "Example of using loops and vars to rename tracks and clips."
3 | Author: "Centomila"
4 |
5 | // Go to the first track
6 | select_track1
7 |
8 |
9 | // Set variables
10 | var trackName = "My Track"
11 | var clipLength = 4
12 | var basePosition = 4
13 |
14 | // Loop to rename for 8 tracks
15 | for (i=1 to 8) {
16 | Track Rename ("${trackName} n. ${i}")
17 | Select next track
18 | }
19 |
20 | select_track1
21 |
22 |
23 | // Use loops with the variables
24 | for (i = 1 to 4) {
25 | Clip Create(${i}, ${clipLength})
26 | Clip Rename ("${trackName} n. ${i}")
27 | Clip Color("#${i*2}F0000")
28 | }
29 |
30 |
31 |
32 | // Create clips with calculated positions and lengths
33 | for (i = 1 to 4) {
34 | // This is a comment!
35 | Clip Create(${i+basePosition}, ${clipLength*i/2})
36 | Clip Rename ("${trackName} n. ${i+basePosition}")
37 | Clip Color("#FF1${i+1*2}${i*4}0")
38 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipLengthCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to set the length of the currently selected clip.
9 | */
10 | public class ClipLengthCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | double length = Double.parseDouble(params[0].trim());
20 | // extension.getLauncherOrArrangerAsClip().getLoopLength().set(length);
21 | ClipUtils.setLoopLength(extension.getLauncherOrArrangerAsClip(), 0.0, length);
22 |
23 | } catch (NumberFormatException e) {
24 | reportError("Invalid length value: " + params[0], extension);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackDeleteCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to delete a track by index.
8 | */
9 | public class TrackDeleteCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | int trackIndex = Integer.parseInt(params[0].trim()) - 1; // Convert from 1-based to 0-based index
19 | extension.trackBank.getItemAt(trackIndex).deleteObject();
20 | } catch (NumberFormatException e) {
21 | reportError("Invalid track index: " + params[0], extension);
22 | } catch (IndexOutOfBoundsException e) {
23 | reportError("Track index out of range: " + params[0], extension);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/bb/BBToggleLauncherArrangerModeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.bb;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.EnumValue;
7 | import com.bitwig.extension.controller.api.SettableEnumValue;
8 |
9 | /**
10 | * Command to toggle between Launcher and Arranger modes.
11 | */
12 | public class BBToggleLauncherArrangerModeCommand extends BaseCommand {
13 |
14 | @Override
15 | public void execute(String[] params, BitwigBuddyExtension extension) {
16 | // String currentMode = ((EnumValue) ModeSelectSettings.toggleLauncherArrangerSetting).get();
17 | String currentMode = ModeSelectSettings.getCurrentLauncherArrangerToggleString();
18 | String newMode = currentMode.equals("Launcher") ? "Arranger" : "Launcher";
19 | ((SettableEnumValue) ModeSelectSettings.toggleLauncherArrangerSetting).set(newMode);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/assembly/distribution.xml:
--------------------------------------------------------------------------------
1 |
4 | distribution
5 |
6 | zip
7 |
8 | false
9 |
10 |
11 |
12 | ${project.build.directory}/${project.build.finalName}.jar
13 | /
14 | BitwigBuddy.bwextension
15 |
16 |
17 |
18 |
19 |
20 | src/main/java/com/centomila/customPresetsTxt/
21 | BitwigBuddy
22 |
23 | **/**/*.*
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report / Feature Request
3 | about: Create a bug report or feature request for BeatBuddy Extension
4 | title: "[BUG/FEATURE] - Brief Description"
5 | labels: ''
6 | assignees: 'centomila'
7 | ---
8 |
9 | ## Issue Type
10 | - [ ] Bug Report
11 | - [ ] Feature Request
12 | - [ ] Question/Support
13 |
14 | ## Description
15 | A clear and concise description of the issue or feature request.
16 |
17 | ## Steps to Reproduce (for bugs)
18 | 1. Go to '...'
19 | 2. Click on '....'
20 | 3. Scroll down to '....'
21 | 4. See error
22 |
23 | ## Expected Behavior
24 | A clear and concise description of what you expected to happen.
25 |
26 | ## Actual Behavior (for bugs)
27 | What actually happened instead.
28 |
29 | ## Screenshots
30 | If applicable, add screenshots to help explain your problem.
31 |
32 | ## Environment
33 | - Bitwig Studio version: [e.g. 5.0.5]
34 | - BitwigBuddy Extension version: [e.g. 1.0.0]
35 | - Operating System: [e.g. Windows 11, macOS 13.0, Ubuntu 22.04]
36 |
37 | ## Additional Context
38 | Add any other context about the problem here.
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipDeleteCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.bitwig.extension.controller.api.DeleteableObject;
4 | import com.centomila.BitwigBuddyExtension;
5 | import com.centomila.ModeSelectSettings;
6 | import com.centomila.utils.commands.BaseCommand;
7 |
8 | /**
9 | * Command to delete the currently selected clip.
10 | */
11 | public class ClipDeleteCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | String currentMode = ModeSelectSettings.getCurrentLauncherArrangerToggleString();
16 |
17 | if (currentMode.equals("Arranger")) {
18 | // In Arranger mode, use the application's delete action to delete the selected clip
19 | extension.getApplication().remove();
20 |
21 | } else if (currentMode.equals("Launcher")) {
22 | // In Launcher mode, delete the selected clip
23 | extension.getLauncherOrArrangerAsClip().clipLauncherSlot().deleteObject();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedIsMutedCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to mute/unmute selected note steps.
12 | */
13 | public class StepSelectedIsMutedCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | boolean isMuted = Boolean.parseBoolean(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setIsMuted(isMuted);
26 | }
27 | } catch (Exception e) {
28 | reportError("Invalid boolean value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackRenameCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to rename the selected track.
8 | */
9 | public class TrackRenameCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
19 | if (currentTrack < 0) {
20 | extension.getHost().println("No track selected, using first track (index 0)");
21 | currentTrack = 0;
22 | }
23 |
24 | String trackName = params[0].trim();
25 | extension.trackBank.getItemAt(currentTrack).name().set(trackName);
26 | } catch (Exception e) {
27 | reportError("Error renaming track: " + e.getMessage(), extension);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2025] [Franco Baccarini / Centomila]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackSelectCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 |
6 | /**
7 | * Command to select a track by index.
8 | */
9 | public class TrackSelectCommand extends BaseCommand {
10 |
11 | @Override
12 | public void execute(String[] params, BitwigBuddyExtension extension) {
13 | if (!validateParamCount(params, 1, extension)) {
14 | return;
15 | }
16 |
17 | try {
18 | int trackIndex = Integer.parseInt(params[0].trim()) - 1;
19 | extension.trackBank.getItemAt(trackIndex).selectInMixer();
20 | extension.trackBank.getItemAt(trackIndex).makeVisibleInArranger();
21 | extension.trackBank.getItemAt(trackIndex).makeVisibleInMixer();
22 | } catch (NumberFormatException e) {
23 | reportError("Invalid track index: " + params[0], extension);
24 | } catch (IndexOutOfBoundsException e) {
25 | reportError("Track index out of range: " + params[0], extension);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedRepeatCountCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the repeat count for selected note steps.
12 | */
13 | public class StepSelectedRepeatCountCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | int count = Integer.parseInt(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setRepeatCount(count);
26 | }
27 | } catch (NumberFormatException e) {
28 | reportError("Invalid repeat count value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Create 8 Tracks.txt:
--------------------------------------------------------------------------------
1 | Macro: "Create 8 Tracks"
2 | Description: "Create eight tracks with colors: Drums, Bass, Bass 2, Pad, Keys, Lead, Arp, and Vocals."
3 | Author: "Centomila"
4 |
5 | // Track 1: Drums (Red)
6 | Create Instrument Track
7 | Track Color ("D32F2F")
8 | Track Rename ("Drums")
9 |
10 |
11 | // Track 2: Bass (Green)
12 | Create Instrument Track
13 | Track Color ("43A047")
14 | Track Rename ("Bass")
15 |
16 | // Track 3: Bass 2 (Teal)
17 | Create Instrument Track
18 | Track Color ("00897B")
19 | Track Rename ("Bass 2")
20 |
21 | // Track 4: Pad (Violet)
22 | Create Instrument Track
23 | Track Color ("7B1FA2")
24 | Track Rename ("Pad")
25 |
26 | // Track 5: Keys (Yellow)
27 | Create Instrument Track
28 | Track Color ("F9A825")
29 | Track Rename ("Keys")
30 |
31 | // Track 6: Lead (Cyan)
32 | Create Instrument Track
33 | Track Color ("00ACC1")
34 | Track Rename ("Lead")
35 |
36 | // Track 7: Arp (Fuchsia)
37 | Create Instrument Track
38 | Track Color ("C2185B")
39 | Track Rename ("Arp")
40 |
41 | // Track 8: Vocals (Pink)
42 | Create Audio Track
43 | Track Color ("EC407A")
44 | Track Rename ("Vocals")
45 |
46 | Track Select (1)
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedIsChanceEnabledCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to enable/disable chance for selected note steps.
12 | */
13 | public class StepSelectedIsChanceEnabledCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | boolean isEnabled = Boolean.parseBoolean(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setIsChanceEnabled(isEnabled);
26 | }
27 | } catch (Exception e) {
28 | reportError("Invalid boolean value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedIsRepeatEnabledCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to enable/disable repeat for selected note steps.
12 | */
13 | public class StepSelectedIsRepeatEnabledCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | boolean isEnabled = Boolean.parseBoolean(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setIsRepeatEnabled(isEnabled);
26 | }
27 | } catch (Exception e) {
28 | reportError("Invalid boolean value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedRepeatCurveCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the repeat timing curve for selected note steps.
12 | */
13 | public class StepSelectedRepeatCurveCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double curve = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setRepeatCurve(curve);
26 | }
27 | } catch (NumberFormatException e) {
28 | reportError("Invalid repeat curve value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedIsOccurrenceEnabledCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to enable/disable occurrence for selected note steps.
12 | */
13 | public class StepSelectedIsOccurrenceEnabledCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | boolean isEnabled = Boolean.parseBoolean(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setIsOccurrenceEnabled(isEnabled);
26 | }
27 | } catch (Exception e) {
28 | reportError("Invalid boolean value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedIsRecurrenceEnabledCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to enable/disable recurrence for selected note steps.
12 | */
13 | public class StepSelectedIsRecurrenceEnabledCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | boolean isEnabled = Boolean.parseBoolean(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setIsRecurrenceEnabled(isEnabled);
26 | }
27 | } catch (Exception e) {
28 | reportError("Invalid boolean value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedRepeatVelocityEndCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the end velocity for note repeats.
12 | */
13 | public class StepSelectedRepeatVelocityEndCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double velocityEnd = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setRepeatVelocityEnd(velocityEnd);
26 | }
27 | } catch (NumberFormatException e) {
28 | reportError("Invalid repeat velocity end value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedRepeatVelocityCurveCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the repeat velocity curve for selected note steps.
12 | */
13 | public class StepSelectedRepeatVelocityCurveCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double curve = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | for (NoteStep note : selectedNotes) {
25 | note.setRepeatVelocityCurve(curve);
26 | }
27 | } catch (NumberFormatException e) {
28 | reportError("Invalid repeat velocity curve value: " + params[0], extension);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedPanCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the pan value of selected note steps.
12 | */
13 | public class StepSelectedPanCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double pan = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setPan(pan);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid pan value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedGainCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the gain of selected note steps.
12 | */
13 | public class StepSelectedGainCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double gain = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setGain(gain);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid gain value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedTimbreCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the timbre of selected note steps.
12 | */
13 | public class StepSelectedTimbreCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double timbre = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setTimbre(timbre);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid timbre value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedChanceCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the chance value of selected note steps.
12 | */
13 | public class StepSelectedChanceCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double chance = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setChance(chance);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid chance value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/ListCommandsCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.centomila.utils.commands.CommandRegistration;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Command to list all registered commands in the system.
11 | * Useful for debugging and documentation purposes.
12 | */
13 | public class ListCommandsCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | List allCommands = CommandRegistration.getAllRegisteredCommands();
18 |
19 | // Display total count
20 | extension.getHost().println("[BeatBuddy] === ALL REGISTERED COMMANDS (" + allCommands.size() + " total) ===");
21 |
22 | // List all commands alphabetically
23 | allCommands.stream()
24 | .sorted()
25 | .forEach(cmd -> extension.getHost().println("[BeatBuddy] " + cmd));
26 |
27 | // Open console so the user can see the output
28 | extension.getApplication().getAction("show_controller_script_console").invoke();
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedRecurrenceCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set recurrence pattern for selected note steps.
12 | */
13 | public class StepSelectedRecurrenceCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 2, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | int length = Integer.parseInt(params[0].trim());
23 | int mask = Integer.parseInt(params[1].trim());
24 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
25 | for (NoteStep note : selectedNotes) {
26 | note.setRecurrence(length, mask);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid recurrence parameters: " + params[0] + ", " + params[1], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedTransposeCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the transpose value of selected note steps.
12 | */
13 | public class StepSelectedTransposeCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | int transpose = Integer.parseInt(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setTranspose(transpose);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid transpose value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedLengthCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the length of selected note steps.
12 | */
13 | public class StepSelectedLengthCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double stepLength = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 |
26 | for (NoteStep note : selectedNotes) {
27 | note.setDuration(stepLength);
28 | }
29 | } catch (NumberFormatException e) {
30 | reportError("Invalid length value: " + params[0], extension);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedOccurrenceCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteOccurrence;
7 | import com.bitwig.extension.controller.api.NoteStep;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Command to set the occurrence condition for selected note steps.
13 | */
14 | public class StepSelectedOccurrenceCommand extends BaseCommand {
15 |
16 | @Override
17 | public void execute(String[] params, BitwigBuddyExtension extension) {
18 | if (!validateParamCount(params, 1, extension)) {
19 | return;
20 | }
21 |
22 | try {
23 | NoteOccurrence condition = NoteOccurrence.valueOf(params[0].trim());
24 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
25 | for (NoteStep note : selectedNotes) {
26 | note.setOccurrence(condition);
27 | }
28 | } catch (IllegalArgumentException e) {
29 | reportError("Invalid occurrence value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedPressureCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the pressure (aftertouch) of selected note steps.
12 | */
13 | public class StepSelectedPressureCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double pressure = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setPressure(pressure);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid pressure value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedVelocityCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the velocity of selected note steps.
12 | */
13 | public class StepSelectedVelocityCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double stepVelocity = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 |
26 | for (NoteStep note : selectedNotes) {
27 | note.setVelocity(stepVelocity);
28 | }
29 | } catch (NumberFormatException e) {
30 | reportError("Invalid velocity value: " + params[0], extension);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackColorCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.api.Color;
6 |
7 | /**
8 | * Command to set the color of the selected track.
9 | */
10 | public class TrackColorCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 1, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
20 | if (currentTrack < 0) {
21 | extension.getHost().println("No track selected, using first track (index 0)");
22 | currentTrack = 0;
23 | }
24 |
25 | String trackColorStr = params[0].trim();
26 | Color trackColor = Color.fromHex(trackColorStr);
27 | extension.trackBank.getItemAt(currentTrack).color().set(trackColor);
28 | } catch (Exception e) {
29 | reportError("Invalid color format or track index: " + e.getMessage(), extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedVelocitySpreadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the velocity spread of selected note steps.
12 | */
13 | public class StepSelectedVelocitySpreadCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double velocitySpread = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setVelocitySpread(velocitySpread);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid velocity spread value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSelectedReleaseVelocityCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ClipUtils;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.NoteStep;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Command to set the release velocity of selected note steps.
12 | */
13 | public class StepSelectedReleaseVelocityCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | double releaseVelocity = Double.parseDouble(params[0].trim());
23 | List selectedNotes = ClipUtils.getSelectedNotes(extension);
24 | extension.getHost().println("Selected notes: " + selectedNotes.size());
25 | for (NoteStep note : selectedNotes) {
26 | note.setReleaseVelocity(releaseVelocity);
27 | }
28 | } catch (NumberFormatException e) {
29 | reportError("Invalid release velocity value: " + params[0], extension);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/SelectDrumPadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.drum;
2 |
3 | import com.bitwig.extension.controller.api.Device;
4 | import com.centomila.BitwigBuddyExtension;
5 | import com.centomila.Utils;
6 | import com.centomila.utils.DrumPadUtils;
7 | import com.centomila.utils.commands.BaseCommand;
8 |
9 | /**
10 | * Command to select a drum pad by note name.
11 | */
12 | public class SelectDrumPadCommand extends BaseCommand {
13 |
14 | @Override
15 | public void execute(String[] params, BitwigBuddyExtension extension) {
16 | if (!validateParamCount(params, 1, extension)) {
17 | return;
18 | }
19 |
20 | try {
21 | // Subscribe to the device and drum pads if needed
22 | final Device device = DrumPadUtils.subscribeToDrumPads(extension);
23 |
24 | String noteNameFull = params[0].trim();
25 | int midiNote = Utils.getMIDINoteNumberFromString(noteNameFull);
26 | extension.drumPadBank.scrollPosition().set(0);
27 | extension.drumPadBank.getItemAt(midiNote).selectInEditor();
28 |
29 | // Unsubscribe from the device and drum pads if needed
30 | DrumPadUtils.unsubscribeFromDrumPads(extension, device);
31 | } catch (Exception e) {
32 | reportError("Failed to select drum pad: " + e.getMessage(), extension);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Get Functions and Vars.txt:
--------------------------------------------------------------------------------
1 | Macro: "Get Functions and Variables"
2 | Description: "Examples of get functions."
3 | Author: "Centomila"
4 |
5 | // Track and project information example
6 |
7 | // Assign the current track name to a variable
8 | var trackName = getCurrentTrackName()
9 |
10 | Wait (1500)
11 | // Show the track name in a message popup
12 | Message(Current track name is: ${trackName})
13 |
14 | Wait (1500)
15 | // Get track position (number)
16 | var trackNumber = getCurrentTrackNumber()
17 | Message(Track position: ${trackNumber})
18 |
19 | Wait (1500)
20 | // Get device information
21 | var deviceName = getCurrentDeviceName()
22 | Message(Current device: ${deviceName})
23 |
24 | Wait (1500)
25 |
26 | // Get transport information
27 | var bpm = getCurrentBpm()
28 | Message("Project tempo: ${bpm} BPM")
29 |
30 | Wait (1500)
31 |
32 | // Time signature information
33 | var num = getTimeSignatureNumerator()
34 | var denom = getTimeSignatureDenominator()
35 | Message("Time signature: ${num}/${denom}")
36 |
37 |
38 | // Send information to the console for logging - both direct and wrapped syntax
39 | Console("== Bitwig State Information ==")
40 | Console("Track: ${trackName} (#${trackNumber})")
41 |
42 | // Direct function calls
43 | Console("Device: getCurrentDeviceName()")
44 | Console("Tempo: ${getCurrentBpm()} BPM")
45 |
46 | // Mixed syntax test
47 | Console("Time signature: ${getTimeSignatureNumerator()}/${getTimeSignatureDenominator()}")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/InsertFileInDrumPadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.drum;
2 |
3 | import com.bitwig.extension.controller.api.Device;
4 | import com.centomila.BitwigBuddyExtension;
5 | import com.centomila.Utils;
6 | import com.centomila.utils.DrumPadUtils;
7 | import com.centomila.utils.commands.BaseCommand;
8 |
9 | /**
10 | * Command to insert a file into a drum pad.
11 | */
12 | public class InsertFileInDrumPadCommand extends BaseCommand {
13 |
14 | @Override
15 | public void execute(String[] params, BitwigBuddyExtension extension) {
16 | if (!validateParamCount(params, 2, extension)) {
17 | return;
18 | }
19 |
20 | try {
21 | // Subscribe to the device and drum pads if needed
22 | final Device device = DrumPadUtils.subscribeToDrumPads(extension);
23 |
24 | String noteNameFull = params[0].trim();
25 | int midiNote = Utils.getMIDINoteNumberFromString(noteNameFull);
26 | extension.drumPadBank.scrollPosition().set(0);
27 | String filePath = params[1].trim();
28 | extension.drumPadBank.getItemAt(midiNote).insertionPoint().insertFile(filePath);
29 |
30 | // Unsubscribe from the device and drum pads if needed
31 | DrumPadUtils.unsubscribeFromDrumPads(extension, device);
32 |
33 | extension.getHost().println("Inserted file into drum pad: " + noteNameFull + " with file: " + filePath);
34 | } catch (Exception e) {
35 | reportError("Failed to insert file in drum pad: " + e.getMessage(), extension);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/device/InsertDeviceCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.device;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.centomila.utils.ReturnBitwigDeviceUUID;
6 |
7 | import java.util.UUID;
8 | import static com.centomila.utils.PopupUtils.showPopup;
9 |
10 | /**
11 | * Command to insert a Bitwig device in the selected track.
12 | */
13 | public class InsertDeviceCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
23 | if (currentTrack < 0) {
24 | extension.getHost().println("No track selected, using first track (index 0)");
25 | currentTrack = 0;
26 | }
27 |
28 | UUID deviceUUID = ReturnBitwigDeviceUUID.getDeviceUUID(params[0]);
29 | if (deviceUUID != null) {
30 | extension.trackBank.getItemAt(currentTrack).endOfDeviceChainInsertionPoint()
31 | .insertBitwigDevice(deviceUUID);
32 | } else {
33 | extension.getHost().println("Device not found: " + params[0]);
34 | showPopup("Device not found: " + params[0]);
35 | }
36 | } catch (Exception e) {
37 | reportError("Error inserting device: " + e.getMessage(), extension);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/step/StepSetCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.step;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.controller.api.Clip;
6 |
7 | /**
8 | * Command to set a step value using the Bitwig API.
9 | */
10 | public class StepSetCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateMinParamCount(params, 5, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | int channel = Integer.parseInt(params[0]);
20 | int stepIndex = Integer.parseInt(params[1]);
21 | int noteDestination = Integer.parseInt(params[2]);
22 | int velocity = Integer.parseInt(params[3]);
23 | double duration = Double.parseDouble(params[4]);
24 |
25 | Clip clip = extension.getLauncherOrArrangerAsClip();
26 | if (clip == null) {
27 | extension.getHost().errorln("No clip is currently selected.");
28 | return;
29 | }
30 |
31 | // Call the API method to set the step value
32 | extension.getHost().println("Setting step " + stepIndex + " on channel " + channel + " to value: " + velocity);
33 | clip.setStep(channel, stepIndex, noteDestination, velocity, duration);
34 | } catch (NumberFormatException e) {
35 | extension.getHost().errorln("Invalid number format in parameters: " + e.getMessage());
36 | } catch (Exception e) {
37 | extension.getHost().errorln("Error setting step: " + e.getMessage());
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/device/InsertVST3Command.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.device;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.centomila.utils.ReturnVST3StringID;
6 | import static com.centomila.utils.PopupUtils.showPopup;
7 |
8 | /**
9 | * Command to insert a VST3 plugin in the selected track.
10 | */
11 | public class InsertVST3Command extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | if (!validateParamCount(params, 1, extension)) {
16 | return;
17 | }
18 |
19 | try {
20 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
21 | if (currentTrack < 0) {
22 | extension.getHost().println("No track selected, using first track (index 0)");
23 | currentTrack = 0;
24 | }
25 |
26 | String vst3Name = params[0].trim();
27 | String VST3StringID = ReturnVST3StringID.getVST3StringID(vst3Name);
28 | showPopup(vst3Name + " - " + VST3StringID);
29 |
30 | if (VST3StringID != null) {
31 | extension.trackBank.getItemAt(currentTrack).endOfDeviceChainInsertionPoint()
32 | .insertVST3Device(VST3StringID);
33 | } else {
34 | extension.getHost().println("VST3 not found: " + vst3Name + " - " + VST3StringID);
35 | showPopup(VST3StringID + " not found: " + vst3Name + " - " + VST3StringID);
36 | }
37 | } catch (Exception e) {
38 | reportError("Error inserting VST3 device: " + e.getMessage(), extension);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/PrintActionsCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.GlobalPreferences;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | import java.io.FileNotFoundException;
8 | import java.io.PrintWriter;
9 | import java.io.UnsupportedEncodingException;
10 |
11 | /**
12 | * Command to print all available actions to the console and save them to a file.
13 | */
14 | public class PrintActionsCommand extends BaseCommand {
15 |
16 | @Override
17 | public void execute(String[] params, BitwigBuddyExtension extension) {
18 | int actionsQty = extension.application.getActions().length;
19 |
20 | // Print actions to console
21 | for (int i = 0; i < actionsQty; i++) {
22 | extension.getHost().println(extension.application.getActions()[i].getName());
23 | }
24 |
25 | // Open console
26 | extension.getApplication().getAction("show_controller_script_console").invoke();
27 |
28 | // Save actions to file
29 | String path = GlobalPreferences.getCurrentPresetsPath() + "/Actions.txt";
30 | try {
31 | PrintWriter writer = new PrintWriter(path, "UTF-8");
32 | for (int i = 0; i < actionsQty; i++) {
33 | writer.println(extension.application.getActions()[i].getId() + " | "
34 | + extension.application.getActions()[i].getName());
35 | }
36 | writer.close();
37 | } catch (FileNotFoundException | UnsupportedEncodingException e) {
38 | reportError("Failed to save actions list: " + e.getMessage(), extension);
39 | e.printStackTrace();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/macro/state/BitwigStateProvider.java:
--------------------------------------------------------------------------------
1 | package com.centomila.macro.state;
2 |
3 | /**
4 | * Interface for providing state information from Bitwig Studio.
5 | * Allows macro scripts to access runtime values from the DAW.
6 | */
7 | public interface BitwigStateProvider {
8 | // Track related methods
9 | String getCurrentTrackName();
10 | int getCurrentTrackNumber();
11 | String getCurrentTrackColor();
12 | boolean isCurrentTrackMuted();
13 | boolean isCurrentTrackSoloed();
14 | boolean isCurrentTrackArmed();
15 | double getCurrentTrackVolume();
16 | double getCurrentTrackPan();
17 | int getTrackCount();
18 |
19 | // Device related methods
20 | String getCurrentDeviceName();
21 | boolean isCurrentDeviceEnabled();
22 | boolean isCurrentDeviceWindowOpen();
23 | int getDeviceCount();
24 |
25 | // Clip related methods
26 | String getCurrentClipName();
27 | String getCurrentClipColor();
28 | boolean isCurrentClipLooping();
29 | double getCurrentClipLength();
30 | boolean isCurrentClipPlaying();
31 | boolean isCurrentClipRecording();
32 | boolean isCurrentClipSelected();
33 |
34 | // Transport related methods
35 | double getCurrentBpm();
36 | int getTimeSignatureNumerator();
37 | int getTimeSignatureDenominator();
38 | boolean isPlaying();
39 | boolean isRecording();
40 | double getPlayPosition();
41 | boolean isMetronomeEnabled();
42 | boolean isArrangerLoopEnabled();
43 |
44 | // Project related methods
45 | String getProjectName();
46 |
47 | // Scene related methods
48 | int getCurrentSceneIndex();
49 | String getCurrentSceneName();
50 |
51 | // Utility methods
52 | boolean supportsMethod(String methodName);
53 | Object callMethod(String methodName);
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/track/TrackColorAllCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.track;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.api.Color;
6 | import com.bitwig.extension.controller.api.Track;
7 |
8 | /**
9 | * Command to set the color of all tracks in the track bank.
10 | */
11 | public class TrackColorAllCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | if (!validateParamCount(params, 1, extension)) {
16 | return;
17 | }
18 |
19 | try {
20 | String trackColorStr = params[0].trim();
21 | Color trackColor = Color.fromHex(trackColorStr);
22 | int trackCount = extension.trackBank.getSizeOfBank();
23 |
24 | // Apply color to all visible tracks in the trackbank
25 | int coloredCount = 0;
26 | for (int i = 0; i < trackCount; i++) {
27 | Track track = extension.trackBank.getItemAt(i);
28 | if (track.exists().get()) {
29 | track.color().set(trackColor);
30 | extension.getHost().println("Applied color to track: " + track.name().get());
31 | coloredCount++;
32 | }
33 | }
34 |
35 | if (coloredCount > 0) {
36 | extension.getHost().println("Applied color to " + coloredCount + " tracks");
37 | } else {
38 | extension.getHost().println("No tracks found to apply color");
39 | }
40 |
41 | } catch (Exception e) {
42 | reportError("Invalid color format or track error: " + e.getMessage(), extension);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/DrumPadUtils.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils;
2 |
3 | import com.bitwig.extension.controller.api.Device;
4 | import com.bitwig.extension.controller.api.DrumPad;
5 | import com.centomila.BitwigBuddyExtension;
6 | import com.centomila.NoteDestinationSettings;
7 |
8 | /**
9 | * Utility class for drum pad operations.
10 | */
11 | public class DrumPadUtils {
12 |
13 | /**
14 | * Subscribes to drum pads if they are not already subscribed.
15 | *
16 | * @param extension The BitwigBuddy extension instance
17 | * @return The device that was subscribed to
18 | */
19 | public static Device subscribeToDrumPads(BitwigBuddyExtension extension) {
20 | Device device = extension.deviceBank.getDevice(0);
21 |
22 | if (!(NoteDestinationSettings.getLearnNoteSelectorAsString()).equals("DM")) {
23 | // Subscribe to the device and drum pads
24 | device.subscribe();
25 | extension.drumPadBank.scrollPosition().set(0);
26 |
27 | for (int i = 0; i < extension.drumPadBank.getSizeOfBank(); i++) {
28 | DrumPad drumPad = extension.drumPadBank.getItemAt(i);
29 | drumPad.subscribe();
30 | }
31 | }
32 |
33 | return device;
34 | }
35 |
36 | /**
37 | * Unsubscribes from drum pads if they were temporarily subscribed.
38 | *
39 | * @param extension The BitwigBuddy extension instance
40 | * @param device The device to unsubscribe from
41 | */
42 | public static void unsubscribeFromDrumPads(BitwigBuddyExtension extension, Device device) {
43 | if (!(NoteDestinationSettings.getLearnNoteSelectorAsString()).equals("DM")) {
44 | for (int i = 0; i < extension.drumPadBank.getSizeOfBank(); i++) {
45 | DrumPad drumPad = extension.drumPadBank.getItemAt(i);
46 | drumPad.unsubscribe();
47 | }
48 | device.unsubscribe();
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/InsertVST3InDrumPadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.drum;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.Utils;
5 | import com.centomila.utils.ReturnVST3StringID;
6 | import com.centomila.utils.commands.BaseCommand;
7 | import com.centomila.utils.DrumPadUtils;
8 | import static com.centomila.utils.PopupUtils.showPopup;
9 |
10 | import com.bitwig.extension.controller.api.Device;
11 |
12 | /**
13 | * Command to insert a VST3 plugin into a drum pad.
14 | */
15 | public class InsertVST3InDrumPadCommand extends BaseCommand {
16 |
17 | @Override
18 | public void execute(String[] params, BitwigBuddyExtension extension) {
19 | if (!validateParamCount(params, 2, extension)) {
20 | return;
21 | }
22 |
23 | try {
24 | // Subscribe to the device and drum pads if needed
25 | final Device device = DrumPadUtils.subscribeToDrumPads(extension);
26 |
27 | String noteNameFull = params[0].trim();
28 | int midiNote = Utils.getMIDINoteNumberFromString(noteNameFull);
29 | extension.drumPadBank.scrollPosition().set(0);
30 | String vst3Name = params[1].trim();
31 | String vst3StringID = ReturnVST3StringID.getVST3StringID(vst3Name);
32 | if (vst3StringID != null) {
33 | extension.drumPadBank.getItemAt(midiNote).insertionPoint().insertVST3Device(vst3StringID);
34 | extension.getHost().println("Inserted VST3 into drum pad: " + noteNameFull + " with VST3: " + vst3Name);
35 | } else {
36 | extension.getHost().println("VST3 not found: " + vst3Name);
37 | showPopup("VST3 not found: " + vst3Name);
38 | }
39 |
40 | // Unsubscribe from the device and drum pads if needed
41 | DrumPadUtils.unsubscribeFromDrumPads(extension, device);
42 | } catch (Exception e) {
43 | reportError("Failed to insert VST3 in drum pad: " + e.getMessage(), extension);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/BitwigBuddyExtensionDefinition.java:
--------------------------------------------------------------------------------
1 | package com.centomila;
2 | import java.util.UUID;
3 |
4 | import com.bitwig.extension.api.PlatformType;
5 | import com.bitwig.extension.controller.AutoDetectionMidiPortNamesList;
6 | import com.bitwig.extension.controller.ControllerExtensionDefinition;
7 | import com.bitwig.extension.controller.api.ControllerHost;
8 |
9 | public class BitwigBuddyExtensionDefinition extends ControllerExtensionDefinition
10 | {
11 | private static final UUID DRIVER_ID = UUID.fromString("27615dbe-6d9f-4bb6-9b32-fe6707040a02");
12 |
13 | public BitwigBuddyExtensionDefinition()
14 | {
15 | }
16 |
17 | @Override
18 | public String getName()
19 | {
20 | return "BitwigBuddy";
21 | }
22 |
23 | @Override
24 | public String getAuthor()
25 | {
26 | return "centomila";
27 | }
28 |
29 | @Override
30 | public String getVersion()
31 | {
32 | return "1.0.0 alpha 2";
33 | }
34 |
35 | @Override
36 | public UUID getId()
37 | {
38 | return DRIVER_ID;
39 | }
40 |
41 | @Override
42 | public String getHardwareVendor()
43 | {
44 | return "centomila";
45 | }
46 |
47 | @Override
48 | public String getHardwareModel()
49 | {
50 | return "BitwigBuddy";
51 | }
52 |
53 | /** {@inheritDoc} */
54 | @Override
55 | public String getHelpFilePath() {
56 | return "https://bitwigbuddy.centomila.com/";
57 | }
58 |
59 | @Override
60 | public int getRequiredAPIVersion()
61 | {
62 | return 20;
63 | }
64 |
65 | @Override
66 | public int getNumMidiInPorts()
67 | {
68 | return 0;
69 | }
70 |
71 | @Override
72 | public int getNumMidiOutPorts()
73 | {
74 | return 0;
75 | }
76 |
77 | @Override
78 | public void listAutoDetectionMidiPortNames(final AutoDetectionMidiPortNamesList list, final PlatformType platformType)
79 | {
80 | }
81 |
82 | @Override
83 | public BitwigBuddyExtension createInstance(final ControllerHost host)
84 | {
85 | return new BitwigBuddyExtension(this, host);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/CreateDrumPadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.drum;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.Utils;
5 | import com.centomila.utils.DrumPadUtils;
6 | import com.centomila.utils.commands.BaseCommand;
7 | import com.bitwig.extension.api.Color;
8 | import com.bitwig.extension.controller.api.Device;
9 |
10 | /**
11 | * Command to create and configure a drum pad.
12 | * `Drum Pad Insert Empty("C#2", "Name", "#D00000)`
13 | */
14 | public class CreateDrumPadCommand extends BaseCommand {
15 |
16 | @Override
17 | public void execute(String[] params, BitwigBuddyExtension extension) {
18 | if (!validateParamCount(params, 3, extension)) {
19 | return;
20 | }
21 |
22 | try {
23 | // Subscribe to the device and drum pads if needed
24 | final Device device = DrumPadUtils.subscribeToDrumPads(extension);
25 |
26 | // Parse parameters
27 | String noteNameFull = params[0].trim();
28 | String drumBankName = params[1].trim();
29 | String drumBankColor = params[2].trim();
30 |
31 | // Convert note name to MIDI note number
32 | int midiNote = Utils.getMIDINoteNumberFromString(noteNameFull);
33 | extension.drumPadBank.scrollPosition().set(0);
34 |
35 | // Create the drum pad
36 | extension.drumPadBank.getItemAt(midiNote).insertionPoint().browse();
37 | extension.application.getAction("Dialog: OK").invoke();
38 |
39 | // Set name and color
40 | extension.drumPadBank.getItemAt(midiNote).name().set(drumBankName);
41 | Color color = Color.fromHex(drumBankColor);
42 | extension.drumPadBank.getItemAt(midiNote).color().set(color);
43 |
44 | // Unsubscribe from the device and drum pads if needed
45 | DrumPadUtils.unsubscribeFromDrumPads(extension, device);
46 | } catch (Exception e) {
47 | reportError("Failed to create drum pad: " + e.getMessage(), extension);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # BitwigBuddy - Bitwig Studio Extension for Generating Drum Patterns (v1.0.0 Alpha 2)
2 |
3 | 
4 |
5 | ## ⚙️ Installation
6 |
7 | 1. ⬇️ Download **_BitwigBuddy-1.0.0-alpha-2.zip_** from the Release page
8 | 2. 📂 Extract the zip to the **_/Bitwig Studio/Extensions/_** folder. Be sure to extract the BitwigBuddy subfolder as well. It contains sample custom presets as txt files.
9 | 1. **Windows:** `%USERPROFILE%\Documents\Bitwig Studio\Extensions`
10 | 1. If your Documents folder is in OneDrive, it might be in `%USERPROFILE%\OneDrive\Documents\Bitwig Studio\Extensions`
11 | 2. **macOS:** `~/Documents/Bitwig Studio/Extensions`
12 | 3. **Linux:** `~/Bitwig Studio/Extensions`
13 | 3. 🟧 In Bitwig, go to **Settings > Controller > Add Extension > Centomila > BitwigBuddy**
14 |
15 | For more details, see https://bitwigbuddy.centomila.com/guide/bitwigbuddy/installation.html
16 |
17 |
18 | # Changelog
19 |
20 | All the notable changes to this project are documented in this file.
21 |
22 | 📃 [View Changelog](CHANGELOG)
23 |
24 | # 🚀 Coming Soon
25 |
26 | Check all the upcoming features and improvements in the [Project Page](https://github.com/users/centomila/projects/3)
27 |
28 | # Support me on Patreon
29 |
30 | Do you like this project? Consider [supporting me on Patreon!](https://www.patreon.com/centomila)
31 |
32 | [](https://www.patreon.com/centomila)
33 |
34 | # Listen to my Music
35 |
36 | Do you like this project? Perhaps you'll enjoy my music as well!😳
37 |
38 | - [YouTube](https://www.youtube.com/@centomila)
39 | - [Spotify](https://open.spotify.com/artist/6bdrEk5R3Ic7nZUufyUfsE)
40 | - [Apple Music](https://music.apple.com/us/artist/centomila/962423083)
41 | - [Tidal](https://tidal.com/browse/artist/32065687/)
42 | - [Qobuz](https://play.qobuz.com/artist/24750477)
43 | - [Zvuk](https://zvuk.com/artist/3300399)
44 | - [Deezer](https://www.deezer.com/artist/7463204)
45 | - [Amazon Music](https://music.amazon.com/artists/B0B12FQRKF/centomila)
46 | - [SoundCloud](https://soundcloud.com/centomila)
47 | - [Beatport](https://www.beatport.com/artist/centomila/1136112)
48 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/CommandFactory.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | /**
10 | * Factory class for creating and retrieving command objects.
11 | * This class centralizes command registration and lookup.
12 | */
13 | public class CommandFactory {
14 |
15 | /**
16 | * Interface for all commands that can be executed by the extension
17 | */
18 | public interface BitwigCommand {
19 | /**
20 | * Executes the command with the given parameters
21 | *
22 | * @param params Parameters parsed from the command string
23 | * @param extension The extension instance providing access to Bitwig API
24 | */
25 | void execute(String[] params, BitwigBuddyExtension extension);
26 | }
27 |
28 | // Registry of all available commands
29 | private static final Map commandRegistry = new HashMap<>();
30 |
31 | /**
32 | * Registers a command with the factory
33 | *
34 | * @param commandName The name of the command (action ID)
35 | * @param command The command implementation
36 | */
37 | public static void registerCommand(String commandName, BitwigCommand command) {
38 | commandRegistry.put(commandName, command);
39 | }
40 |
41 | /**
42 | * Retrieves a command from the registry
43 | *
44 | * @param commandName The name of the command to retrieve
45 | * @return The command implementation, or null if not found
46 | */
47 | public static BitwigCommand getCommand(String commandName) {
48 | return commandRegistry.get(commandName);
49 | }
50 |
51 | /**
52 | * Checks if a command exists in the registry
53 | *
54 | * @param commandName The name of the command to check
55 | * @return true if the command exists, false otherwise
56 | */
57 | public static boolean hasCommand(String commandName) {
58 | return commandRegistry.containsKey(commandName);
59 | }
60 |
61 | /**
62 | * Gets all registered command names
63 | *
64 | * @return List of command names
65 | */
66 | public static List getAllCommandNames() {
67 | return new ArrayList<>(commandRegistry.keySet());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/drum/InsertBitwigDeviceInDrumPadCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.drum;
2 |
3 | import com.bitwig.extension.controller.api.Device;
4 | import com.centomila.BitwigBuddyExtension;
5 | import com.centomila.Utils;
6 | import com.centomila.utils.commands.BaseCommand;
7 | import com.centomila.utils.DrumPadUtils;
8 |
9 | import java.util.UUID;
10 |
11 | import static com.centomila.utils.PopupUtils.showPopup;
12 |
13 | /**
14 | * Command to insert a Bitwig device in a drum pad.
15 | */
16 | public class InsertBitwigDeviceInDrumPadCommand extends BaseCommand {
17 |
18 | @Override
19 | public void execute(String[] params, BitwigBuddyExtension extension) {
20 | if (!validateParamCount(params, 2, extension)) {
21 | return;
22 | }
23 |
24 | try {
25 | int bankSize = extension.deviceBank.getSizeOfBank();
26 | if (bankSize == 0) {
27 | extension.getHost().println("No devices found in the bank.");
28 | showPopup("No devices found in the bank.");
29 | return;
30 | }
31 |
32 | // Subscribe to the device and drum pads if needed
33 | final Device device = DrumPadUtils.subscribeToDrumPads(extension);
34 |
35 | String noteNameFull = params[0].trim();
36 | int midiNote = Utils.getMIDINoteNumberFromString(noteNameFull);
37 | extension.drumPadBank.scrollPosition().set(0);
38 |
39 | UUID deviceUUID = getDeviceUUID(params[1].trim());
40 | if (deviceUUID != null) {
41 | extension.drumPadBank.getItemAt(midiNote).insertionPoint().insertBitwigDevice(deviceUUID);
42 | } else {
43 | extension.getHost().println("Device not found: " + params[1]);
44 | showPopup("Device not found: " + params[1]);
45 | }
46 |
47 | // Unsubscribe from the device and drum pads if needed
48 | DrumPadUtils.unsubscribeFromDrumPads(extension, device);
49 | } catch (Exception e) {
50 | reportError("Error inserting device in drum pad: " + e.getMessage(), extension);
51 | }
52 | }
53 |
54 | private UUID getDeviceUUID(String deviceName) {
55 | // Reuse existing method from ReturnBitwigDeviceUUID or use a simpler approach
56 | return com.centomila.utils.ReturnBitwigDeviceUUID.getDeviceUUID(deviceName);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Melodic Techno.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Melodic Techno (Detailed Cue Markers)"
2 | Description: "Cue Markers for a Melodic Techno Track."
3 | Author: "Centomila"
4 | Bpm (124)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 | Wait (200)
9 |
10 | // Atmospheric intro
11 | jump_to_beginning_of_arranger_window
12 | Wait (100)
13 | insert_arranger_cue_marker_at_play_position
14 | CueMarkerName (1, "Intro - Pads & Atmos")
15 |
16 | // 16 bars - Kick & basic bass elements enter
17 | jump_forward_8_bars
18 | jump_forward_8_bars
19 | Wait (100)
20 | insert_arranger_cue_marker_at_play_position
21 | CueMarkerName (2, "Kick & Bass Intro")
22 |
23 | // 16 bars - Main groove with percussion fills
24 | jump_forward_8_bars
25 | jump_forward_8_bars
26 | Wait (100)
27 | insert_arranger_cue_marker_at_play_position
28 | CueMarkerName (3, "Main Groove")
29 |
30 | // 16 bars - First build-up section
31 | jump_forward_8_bars
32 | jump_forward_8_bars
33 | Wait (100)
34 | insert_arranger_cue_marker_at_play_position
35 | CueMarkerName (4, "Build-Up")
36 |
37 | // 16 bars - First main section with lead elements
38 | jump_forward_8_bars
39 | jump_forward_8_bars
40 | Wait (100)
41 | insert_arranger_cue_marker_at_play_position
42 | CueMarkerName (5, "First Main Section")
43 |
44 | // 16 bars - Breakdown with atmospheric elements
45 | jump_forward_8_bars
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (6, "Breakdown")
50 |
51 | // 16 bars - Tension building section
52 | jump_forward_8_bars
53 | jump_forward_8_bars
54 | Wait (100)
55 | insert_arranger_cue_marker_at_play_position
56 | CueMarkerName (7, "Second Build-Up")
57 |
58 | // 16 bars - Second main section (climax)
59 | jump_forward_8_bars
60 | jump_forward_8_bars
61 | Wait (100)
62 | insert_arranger_cue_marker_at_play_position
63 | CueMarkerName (8, "Main Peak Section")
64 |
65 | // 16 bars - Energy sustain section
66 | jump_forward_8_bars
67 | jump_forward_8_bars
68 | Wait (100)
69 | insert_arranger_cue_marker_at_play_position
70 | CueMarkerName (9, "Sustain Section")
71 |
72 | // 16 bars - Gradual elements removal
73 | jump_forward_8_bars
74 | jump_forward_8_bars
75 | Wait (100)
76 | insert_arranger_cue_marker_at_play_position
77 | CueMarkerName (10, "Elements Removal")
78 |
79 | // 16 bars - Outro with pad and atmosphere
80 | jump_forward_8_bars
81 | jump_forward_8_bars
82 | Wait (100)
83 | insert_arranger_cue_marker_at_play_position
84 | CueMarkerName (11, "Outro")
85 |
86 | Message ("Melodic Techno Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/BaseCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.PopupUtils;
5 |
6 | /**
7 | * Base abstract class for all command implementations.
8 | * Provides common functionality for command execution.
9 | */
10 | public abstract class BaseCommand implements CommandFactory.BitwigCommand {
11 |
12 | /**
13 | * Validates that the command has a specific number of parameters
14 | *
15 | * @param params The parameters array
16 | * @param expectedCount The expected number of parameters
17 | * @param extension The extension instance for error reporting
18 | * @return true if validation passes, false if it fails
19 | */
20 | protected boolean validateParamCount(String[] params, int expectedCount, BitwigBuddyExtension extension) {
21 | if (params.length != expectedCount) {
22 | extension.getHost().errorln(getClass().getSimpleName() +
23 | " requires " + expectedCount + " parameters, but " + params.length + " were provided");
24 | PopupUtils.showPopup("Command error: Wrong number of parameters");
25 | return false;
26 | }
27 | return true;
28 | }
29 |
30 | /**
31 | * Validates that the command has at least a minimum number of parameters
32 | *
33 | * @param params The parameters array
34 | * @param minCount The minimum number of parameters
35 | * @param extension The extension instance for error reporting
36 | * @return true if validation passes, false if it fails
37 | */
38 | protected boolean validateMinParamCount(String[] params, int minCount, BitwigBuddyExtension extension) {
39 | if (params.length < minCount) {
40 | extension.getHost().errorln(getClass().getSimpleName() +
41 | " requires at least " + minCount + " parameters, but " + params.length + " were provided");
42 | PopupUtils.showPopup("Command error: Not enough parameters");
43 | return false;
44 | }
45 | return true;
46 | }
47 |
48 | /**
49 | * Reports an error during command execution
50 | *
51 | * @param message The error message
52 | * @param extension The extension instance for error reporting
53 | */
54 | protected void reportError(String message, BitwigBuddyExtension extension) {
55 | extension.getHost().errorln(getClass().getSimpleName() + ": " + message);
56 | PopupUtils.showPopup("Command error: " + message);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipSelectCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 |
7 | /**
8 | * Command to select a clip.
9 | * If an index parameter is provided, selects a specific clip in the launcher.
10 | * Without a parameter, selects the current clip.
11 | */
12 | public class ClipSelectCommand extends BaseCommand {
13 |
14 | @Override
15 | public void execute(String[] params, BitwigBuddyExtension extension) {
16 | // If no parameters, select the current clip
17 | if (params.length == 0) {
18 | extension.getLauncherOrArrangerAsClip().clipLauncherSlot().select();
19 | return;
20 | }
21 |
22 | try {
23 | // If we're in launcher mode and an index is provided, select the clip at that index
24 | if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Launcher")) {
25 | // Get the current track index
26 | int trackIndex = extension.trackBank.cursorIndex().getAsInt();
27 | if (trackIndex < 0) {
28 | extension.getHost().println("No track selected, using first track (index 0)");
29 | trackIndex = 0;
30 | }
31 |
32 | // Parse the clip index parameter (1-based in the command, converted to 0-based)
33 | int slotIndex = Integer.parseInt(params[0].trim()) - 1;
34 |
35 | if (slotIndex >= 0 && slotIndex < 128) {
36 | // Select the clip at the specified index
37 | extension.trackBank.getItemAt(trackIndex).clipLauncherSlotBank().getItemAt(slotIndex).select();
38 | extension.getHost().println("Selected clip at index: " + (slotIndex + 1));
39 | } else {
40 | reportError("Invalid slot index: " + (slotIndex + 1), extension);
41 | }
42 | } else {
43 | // In arranger mode, we can't select by index, so just select current clip
44 | extension.getLauncherOrArrangerAsClip().clipLauncherSlot().select();
45 | extension.getHost().println("In Arranger mode, index parameter is ignored");
46 | }
47 | } catch (NumberFormatException e) {
48 | reportError("Invalid index parameter: " + params[0], extension);
49 | } catch (IndexOutOfBoundsException e) {
50 | reportError("Index out of bounds: " + params[0], extension);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/EditClipSettings.java:
--------------------------------------------------------------------------------
1 | package com.centomila;
2 |
3 | import static com.centomila.utils.PopupUtils.showPopup;
4 | import static com.centomila.utils.SettingsHelper.createSignalSetting;
5 | import static com.centomila.utils.SettingsHelper.createStringSetting;
6 | import static com.centomila.utils.SettingsHelper.disableSetting;
7 | import static com.centomila.utils.SettingsHelper.hideSetting;
8 | import static com.centomila.utils.SettingsHelper.showSetting;
9 | import static com.centomila.utils.SettingsHelper.titleWithLine;
10 |
11 | import com.bitwig.extension.controller.api.Clip;
12 | import com.bitwig.extension.controller.api.Setting;
13 | import com.bitwig.extension.controller.api.Signal;
14 |
15 | public class EditClipSettings {
16 | private static BitwigBuddyExtension extension;
17 | public static Setting editClipSpacer;
18 | public static Setting editClipBtnSignal;
19 | public static Setting[] allSettings;
20 | private static final String CATEGORY_EDIT_CLIP = "3 Edit Clip";
21 |
22 | public static void init(BitwigBuddyExtension extension) {
23 | EditClipSettings.extension = extension;
24 | initEditClipSettings();
25 | }
26 |
27 | private static void initEditClipSettings() {
28 | editClipSpacer = (Setting) createStringSetting(titleWithLine("EDIT CLIP ------------------------------------"), CATEGORY_EDIT_CLIP,9999,
29 | "---------------------------------------------------");
30 | disableSetting(editClipSpacer);
31 |
32 | editClipBtnSignal = (Setting) createSignalSetting("Update Selected Steps Velocity", CATEGORY_EDIT_CLIP, "Update Selected Steps Velocity");
33 |
34 |
35 | // Obsereve the edit clip button signal
36 | ((Signal) editClipBtnSignal).addSignalObserver(() -> {
37 | editClipAction();
38 | });
39 | allSettings = new Setting[] { editClipSpacer, editClipBtnSignal };
40 | }
41 |
42 | public static void editClipAction() {
43 | // Create an array with the selected notes and randomize the velocity of each note
44 |
45 | // Get the selected clip
46 | Clip clip = extension.getLauncherOrArrangerAsClip();
47 | if (clip == null) {
48 | showPopup("No clip selected");
49 | return;
50 | }
51 |
52 |
53 | try {
54 | ClipUtils.applyVelocityShapeToSelectedNotes(extension);
55 | } catch (Exception e) {
56 |
57 | e.printStackTrace();
58 | }
59 |
60 |
61 |
62 |
63 |
64 | }
65 |
66 | public static void showAllSettings() {
67 | showSetting(allSettings);
68 | }
69 |
70 | public static void hideAllSettings() {
71 | hideSetting(allSettings);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipMoveCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import com.bitwig.extension.controller.api.ClipLauncherSlot;
7 |
8 | import static com.centomila.utils.PopupUtils.showPopup;
9 |
10 | /**
11 | * Command to move the selected clip by a specified amount.
12 | */
13 | public class ClipMoveCommand extends BaseCommand {
14 |
15 | @Override
16 | public void execute(String[] params, BitwigBuddyExtension extension) {
17 | if (!validateParamCount(params, 1, extension)) {
18 | return;
19 | }
20 |
21 | try {
22 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
23 | if (currentTrack < 0) {
24 | extension.getHost().println("No track selected, using first track (index 0)");
25 | currentTrack = 0;
26 | }
27 |
28 | double moveAmount = Double.parseDouble(params[0].trim());
29 |
30 | if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Arranger")) {
31 | moveInArranger(moveAmount, extension);
32 | } else {
33 | moveInLauncher(moveAmount, extension, currentTrack);
34 | }
35 | } catch (NumberFormatException e) {
36 | reportError("Invalid move amount: " + params[0], extension);
37 | }
38 | }
39 |
40 | private void moveInArranger(double moveAmount, BitwigBuddyExtension extension) {
41 | if (moveAmount > 0) {
42 | for (int i = 0; i < moveAmount; i++) {
43 | extension.getApplication().getAction("nudge_events_one_step_later").invoke();
44 | }
45 | } else if (moveAmount < 0) {
46 | for (int i = 0; i < Math.abs(moveAmount); i++) {
47 | extension.getApplication().getAction("nudge_events_one_step_earlier").invoke();
48 | }
49 | }
50 | }
51 |
52 | private void moveInLauncher(double moveAmount, BitwigBuddyExtension extension, int currentTrack) {
53 | ClipLauncherSlot sourceSlot = extension.getLauncherOrArrangerAsClip().clipLauncherSlot();
54 |
55 | int sourceSlotIndex = sourceSlot.sceneIndex().get();
56 | int targetSlotIndex = sourceSlotIndex + (int) moveAmount;
57 |
58 | showPopup("Source slot index: " + sourceSlotIndex + " Target slot index: " + targetSlotIndex);
59 |
60 | if (targetSlotIndex >= 0 && targetSlotIndex < 128) {
61 | extension.trackBank.getItemAt(currentTrack).clipLauncherSlotBank().getItemAt(targetSlotIndex)
62 | .replaceInsertionPoint().moveSlotsOrScenes(sourceSlot);
63 |
64 | extension.trackBank.getItemAt(currentTrack).clipLauncherSlotBank().getItemAt(targetSlotIndex).select();
65 | extension.sceneBank.cursorIndex().set(targetSlotIndex);
66 | } else {
67 | showPopup("Invalid target slot index: " + targetSlotIndex);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/device/InsertFileCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.device;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.ModeSelectSettings;
5 | import com.centomila.utils.commands.BaseCommand;
6 | import static com.centomila.utils.PopupUtils.showPopup;
7 |
8 | /**
9 | * Command to insert a file (preset or sample) into a track.
10 | */
11 | public class InsertFileCommand extends BaseCommand {
12 |
13 | @Override
14 | public void execute(String[] params, BitwigBuddyExtension extension) {
15 | if (!validateParamCount(params, 2, extension)) {
16 | return;
17 | }
18 |
19 | try {
20 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
21 | if (currentTrack < 0) {
22 | extension.getHost().println("No track selected, using first track (index 0)");
23 | currentTrack = 0;
24 | }
25 |
26 | int slotIndexInsertFile = Integer.parseInt(params[0].trim());
27 | String filePath = params[1].trim();
28 |
29 | if (filePath.endsWith(".bwpreset")) {
30 | handlePresetFile(extension, currentTrack, slotIndexInsertFile, filePath);
31 | } else {
32 | handleSampleFile(extension, currentTrack, slotIndexInsertFile, filePath);
33 | }
34 | } catch (NumberFormatException e) {
35 | reportError("Invalid slot index: " + params[0], extension);
36 | } catch (Exception e) {
37 | reportError("Error inserting file: " + e.getMessage(), extension);
38 | }
39 | }
40 |
41 | private void handlePresetFile(BitwigBuddyExtension extension, int currentTrack, int slotIndex, String filePath) {
42 | if (slotIndex == 0) {
43 | extension.trackBank.getItemAt(currentTrack).clipLauncherSlotBank().getItemAt(0).replaceInsertionPoint()
44 | .insertFile(filePath);
45 | } else if (slotIndex > 0) {
46 | extension.trackBank.getItemAt(currentTrack).endOfDeviceChainInsertionPoint().insertFile(filePath);
47 | } else if (slotIndex < 0) {
48 | extension.trackBank.getItemAt(currentTrack).startOfDeviceChainInsertionPoint().insertFile(filePath);
49 | }
50 | }
51 |
52 | private void handleSampleFile(BitwigBuddyExtension extension, int currentTrack, int slotIndex, String filePath) {
53 | if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Launcher")) {
54 | slotIndex = slotIndex - 1;
55 | extension.trackBank.getItemAt(currentTrack).clipLauncherSlotBank()
56 | .createEmptyClip(slotIndex, 4);
57 | extension.trackBank.getItemAt(currentTrack).clipLauncherSlotBank().getItemAt(slotIndex)
58 | .replaceInsertionPoint().insertFile(filePath);
59 | } else if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Arranger")) {
60 | showPopup("I can't insert files in the arranger. Launcher only.");
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/marker/CueMarkerNameCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.marker;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.utils.commands.BaseCommand;
5 | import com.bitwig.extension.controller.api.CueMarker;
6 |
7 | /**
8 | * Command to rename a cue marker.
9 | */
10 | public class CueMarkerNameCommand extends BaseCommand {
11 |
12 | @Override
13 | public void execute(String[] params, BitwigBuddyExtension extension) {
14 | if (!validateParamCount(params, 2, extension)) {
15 | return;
16 | }
17 |
18 | try {
19 | final int itemNumber = Integer.parseInt(params[0].trim()) - 1;
20 | final String name = params[1].trim();
21 |
22 | // Use a longer delay (200ms) to ensure Bitwig has time to register the marker
23 | extension.getHost().scheduleTask(() -> {
24 | try {
25 | // Force a refresh of the cue marker bank
26 | extension.cueMarkerBank.scrollPosition().set(0);
27 |
28 | CueMarker cueMarker = extension.cueMarkerBank.getItemAt(itemNumber);
29 | if (cueMarker != null && cueMarker.exists().get()) {
30 | cueMarker.name().set(name);
31 | extension.getHost().println("Renamed cue marker " + (itemNumber + 1) + " to: " + name);
32 | } else {
33 | // Try refreshing and retrying once if the marker isn't found
34 | extension.getHost().scheduleTask(() -> {
35 | try {
36 | CueMarker retryMarker = extension.cueMarkerBank.getItemAt(itemNumber);
37 | if (retryMarker != null && retryMarker.exists().get()) {
38 | retryMarker.name().set(name);
39 | extension.getHost().println("Renamed cue marker " + (itemNumber + 1) + " to: " + name + " (retry successful)");
40 | } else {
41 | reportError("Cue marker at index " + (itemNumber + 1) + " doesn't exist after retry", extension);
42 | }
43 | } catch (Exception e) {
44 | reportError("Error in retry setting cue marker name: " + e.getMessage(), extension);
45 | }
46 | }, 100); // Additional 100ms delay for retry
47 | }
48 | } catch (IndexOutOfBoundsException e) {
49 | reportError("Cue marker index out of range: " + (itemNumber + 1), extension);
50 | } catch (Exception e) {
51 | reportError("Error setting cue marker name: " + e.getMessage(), extension);
52 | }
53 | }, 500); // Increased delay to 200ms
54 |
55 | } catch (NumberFormatException e) {
56 | reportError("Invalid cue marker index: " + params[0], extension);
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - House.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - House (Detailed Cue Markers)"
2 | Description: "Generate Detailed Cue Markers for a House Track Arrangement."
3 | Author: "Centomila"
4 | Bpm (126)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // Start of track
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "Intro - Ambient")
14 |
15 | // 8 bars - Basic percussion begins
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Basic Percussion")
20 |
21 | // 8 bars - Full drum kit enters
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Full Drums")
26 |
27 | // 8 bars - Bass enters
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements")
32 |
33 | // 8 bars - First build-up begins
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Build-Up 1")
38 |
39 | // 4 bars - Pre-drop tension (using jump_to_beginning_of_next_bar x4)
40 | jump_to_beginning_of_next_bar
41 | jump_to_beginning_of_next_bar
42 | jump_to_beginning_of_next_bar
43 | jump_to_beginning_of_next_bar
44 | Wait (100)
45 | insert_arranger_cue_marker_at_play_position
46 | CueMarkerName (6, "Pre-Drop")
47 |
48 | // 4 bars - First drop (using jump_to_beginning_of_next_bar x4)
49 | jump_to_beginning_of_next_bar
50 | jump_to_beginning_of_next_bar
51 | jump_to_beginning_of_next_bar
52 | jump_to_beginning_of_next_bar
53 | Wait (100)
54 | insert_arranger_cue_marker_at_play_position
55 | CueMarkerName (7, "Drop 1")
56 |
57 | // 16 bars - Main section continues
58 | jump_forward_8_bars
59 | jump_forward_8_bars
60 | Wait (100)
61 | insert_arranger_cue_marker_at_play_position
62 | CueMarkerName (8, "Breakdown")
63 |
64 | // 8 bars - Minimal break section
65 | jump_forward_8_bars
66 | Wait (100)
67 | insert_arranger_cue_marker_at_play_position
68 | CueMarkerName (9, "Break Elements")
69 |
70 | // 8 bars - Build-up to second drop
71 | jump_forward_8_bars
72 | Wait (100)
73 | insert_arranger_cue_marker_at_play_position
74 | CueMarkerName (10, "Build-Up 2")
75 |
76 | // 8 bars - Second drop (main section)
77 | jump_forward_8_bars
78 | Wait (100)
79 | insert_arranger_cue_marker_at_play_position
80 | CueMarkerName (11, "Drop 2")
81 |
82 | // 16 bars - Extended drop section
83 | jump_forward_8_bars
84 | jump_forward_8_bars
85 | Wait (100)
86 | insert_arranger_cue_marker_at_play_position
87 | CueMarkerName (12, "Final Section")
88 |
89 | // 8 bars - Elements removal begins
90 | jump_forward_8_bars
91 | Wait (100)
92 | insert_arranger_cue_marker_at_play_position
93 | CueMarkerName (13, "Outro - Elements Removal")
94 |
95 | // 8 bars - Final outro
96 | jump_forward_8_bars
97 | Wait (100)
98 | insert_arranger_cue_marker_at_play_position
99 | CueMarkerName (14, "Outro - Final")
100 |
101 | Message ("House Arrangement Cue Markers Created")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Pop.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Modern Pop (Detailed Cue Markers)"
2 | Description: "Generate Detailed Cue Markers for a Modern Pop Track Arrangement."
3 | Author: "Centomila"
4 | Bpm (100)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // Start with a short intro
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "Intro - Atmospheric")
14 |
15 | // 4 bars - Vocal intro or hook teaser
16 | jump_to_beginning_of_next_bar
17 | jump_to_beginning_of_next_bar
18 | jump_to_beginning_of_next_bar
19 | jump_to_beginning_of_next_bar
20 | Wait (100)
21 | insert_arranger_cue_marker_at_play_position
22 | CueMarkerName (2, "Intro - Vocal Hook")
23 |
24 | // 8 bars - First verse starts
25 | jump_forward_8_bars
26 | Wait (100)
27 | insert_arranger_cue_marker_at_play_position
28 | CueMarkerName (3, "Verse 1")
29 |
30 | // 4 bars - Pre-chorus build
31 | jump_to_beginning_of_next_bar
32 | jump_to_beginning_of_next_bar
33 | jump_to_beginning_of_next_bar
34 | jump_to_beginning_of_next_bar
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (4, "Pre-Chorus 1")
38 |
39 | // 8 bars - Chorus with hook
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (5, "Chorus 1")
44 |
45 | // 4 bars - Post-chorus hook section
46 | jump_to_beginning_of_next_bar
47 | jump_to_beginning_of_next_bar
48 | jump_to_beginning_of_next_bar
49 | jump_to_beginning_of_next_bar
50 | Wait (100)
51 | insert_arranger_cue_marker_at_play_position
52 | CueMarkerName (6, "Post-Chorus")
53 |
54 | // 8 bars - Second verse
55 | jump_forward_8_bars
56 | Wait (100)
57 | insert_arranger_cue_marker_at_play_position
58 | CueMarkerName (7, "Verse 2")
59 |
60 | // 4 bars - Pre-chorus build
61 | jump_to_beginning_of_next_bar
62 | jump_to_beginning_of_next_bar
63 | jump_to_beginning_of_next_bar
64 | jump_to_beginning_of_next_bar
65 | Wait (100)
66 | insert_arranger_cue_marker_at_play_position
67 | CueMarkerName (8, "Pre-Chorus 2")
68 |
69 | // 8 bars - Second chorus
70 | jump_forward_8_bars
71 | Wait (100)
72 | insert_arranger_cue_marker_at_play_position
73 | CueMarkerName (9, "Chorus 2")
74 |
75 | // 4 bars - Post-chorus hook section
76 | jump_to_beginning_of_next_bar
77 | jump_to_beginning_of_next_bar
78 | jump_to_beginning_of_next_bar
79 | jump_to_beginning_of_next_bar
80 | Wait (100)
81 | insert_arranger_cue_marker_at_play_position
82 | CueMarkerName (10, "Post-Chorus 2")
83 |
84 | // 8 bars - Bridge/breakdown section
85 | jump_forward_8_bars
86 | Wait (100)
87 | insert_arranger_cue_marker_at_play_position
88 | CueMarkerName (11, "Bridge")
89 |
90 | // 4 bars - Build to final chorus
91 | jump_to_beginning_of_next_bar
92 | jump_to_beginning_of_next_bar
93 | jump_to_beginning_of_next_bar
94 | jump_to_beginning_of_next_bar
95 | Wait (100)
96 | insert_arranger_cue_marker_at_play_position
97 | CueMarkerName (12, "Build-Up")
98 |
99 | // 8 bars - Final chorus (often extended or with variations)
100 | jump_forward_8_bars
101 | Wait (100)
102 | insert_arranger_cue_marker_at_play_position
103 | CueMarkerName (13, "Final Chorus")
104 |
105 | // 8 bars - Outro with hook elements
106 | jump_forward_8_bars
107 | Wait (100)
108 | insert_arranger_cue_marker_at_play_position
109 | CueMarkerName (14, "Outro")
110 |
111 | Message ("Modern Pop Arrangement Cue Markers Created")
112 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/OpenWebUrl.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils;
2 |
3 | import java.io.IOException;
4 | import com.bitwig.extension.controller.api.ControllerHost;
5 | import static com.centomila.utils.PopupUtils.showPopup;
6 |
7 | /**
8 | * Utility class for opening URLs in the system's default web browser.
9 | * Provides platform-specific command handling for Windows, macOS, and Linux.
10 | */
11 | public class OpenWebUrl {
12 | /**
13 | * Enum defining platform-specific commands for opening URLs and files.
14 | * Contains command configurations for Windows, macOS, and Linux systems.
15 | */
16 | public enum PlatformCommand {
17 | /** Windows-specific commands using explorer.exe and cmd */
18 | WINDOWS("explorer.exe", "cmd", "/c", "start"),
19 | /** macOS-specific commands using the 'open' command */
20 | MAC("open", "open", "", ""),
21 | /** Linux-specific commands using xdg-open */
22 | LINUX("xdg-open", "xdg-open", "", "");
23 |
24 | final String fileExplorer;
25 | final String browserCommand;
26 | final String browserParam1;
27 | final String browserParam2;
28 |
29 | /**
30 | * Constructs a PlatformCommand with specific command parameters.
31 | *
32 | * @param fileExplorer Command to open file explorer
33 | * @param browserCommand Command to open web browser
34 | * @param browserParam1 First parameter for browser command
35 | * @param browserParam2 Second parameter for browser command
36 | */
37 | PlatformCommand(String fileExplorer, String browserCommand, String browserParam1, String browserParam2) {
38 | this.fileExplorer = fileExplorer;
39 | this.browserCommand = browserCommand;
40 | this.browserParam1 = browserParam1;
41 | this.browserParam2 = browserParam2;
42 | }
43 | }
44 |
45 | /**
46 | * Opens a URL in the system's default web browser.
47 | *
48 | * @param host The Bitwig ControllerHost instance for platform detection
49 | * @param url The URL to open
50 | * @param pageName The name of the page (used for error reporting)
51 | */
52 | public static void openUrl(ControllerHost host, String url, String pageName) {
53 | try {
54 | PlatformCommand cmd = getPlatformCommand(host);
55 | String[] command = cmd.browserParam1.isEmpty()
56 | ? new String[] { cmd.browserCommand, url }
57 | : new String[] { cmd.browserCommand, cmd.browserParam1, cmd.browserParam2, url };
58 |
59 | Runtime.getRuntime().exec(command);
60 | } catch (IOException e) {
61 | host.errorln("Failed to open " + pageName + " page: " + e.getMessage());
62 | showPopup("Please visit " + url + " in your web browser.");
63 | }
64 | }
65 |
66 | /**
67 | * Determines the appropriate platform command configuration based on the host
68 | * system.
69 | *
70 | * @param host The Bitwig ControllerHost instance used for platform detection
71 | * @return The PlatformCommand enum corresponding to the current operating
72 | * system
73 | */
74 | private static PlatformCommand getPlatformCommand(ControllerHost host) {
75 | if (host.platformIsWindows())
76 | return PlatformCommand.WINDOWS;
77 | if (host.platformIsMac())
78 | return PlatformCommand.MAC;
79 | if (host.platformIsLinux())
80 | return PlatformCommand.LINUX;
81 | return null;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/ExtensionPath.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils;
2 |
3 | import java.nio.file.Files;
4 | import java.nio.file.Path;
5 | import java.nio.file.Paths;
6 |
7 | import com.bitwig.extension.controller.api.ControllerHost;
8 |
9 | /**
10 | * Utility class for handling Bitwig Studio extension paths across different operating systems.
11 | * This class helps locate the correct extensions directory based on the user's OS and language settings.
12 | */
13 | public class ExtensionPath {
14 | private static ControllerHost host;
15 |
16 | /**
17 | * Initializes the ExtensionPath utility with a ControllerHost instance.
18 | * This method must be called before using any other methods in this class.
19 | *
20 | * @param controllerHost The Bitwig Studio ControllerHost instance
21 | */
22 | public static void init(ControllerHost controllerHost) {
23 | host = controllerHost;
24 | }
25 |
26 | /**
27 | * Array of localized "Documents" folder names for Windows systems in different languages.
28 | */
29 | private static final String[] WINDOWS_DOCUMENTS_LOCALIZED = {
30 | "Documents", "Documenti", "Documentos", "Dokumente",
31 | "文档", "文書", "문서", "Документы"
32 | };
33 |
34 | /**
35 | * Gets the default path to the Bitwig Studio extensions folder.
36 | * Handles different locations based on operating system:
37 | * - Windows: Checks both OneDrive and regular Documents folders with localization support
38 | * - MacOS: Uses ~/Documents/Bitwig Studio/Extensions
39 | * - Linux: Uses ~/Bitwig Studio/Extensions
40 | *
41 | * @return String representation of the extensions directory path
42 | */
43 | public static String getDefaultExtensionsPath() {
44 | String userHome = System.getProperty("user.home");
45 |
46 | // Windows
47 | if (host.platformIsWindows()) {
48 | // Check OneDrive paths first
49 | Path oneDriveBase = Paths.get(userHome, "OneDrive");
50 | if (Files.exists(oneDriveBase)) {
51 | for (String docName : WINDOWS_DOCUMENTS_LOCALIZED) {
52 | Path path = Paths.get(userHome, "OneDrive", docName, "Bitwig Studio", "Extensions");
53 | if (Files.exists(path)) {
54 | return path.toString();
55 | }
56 | }
57 | }
58 | // Then check regular Documents folders
59 | for (String docName : WINDOWS_DOCUMENTS_LOCALIZED) {
60 | Path path = Paths.get(userHome, docName, "Bitwig Studio", "Extensions");
61 | if (Files.exists(path)) {
62 | return path.toString();
63 | }
64 | }
65 |
66 | // MacOS
67 | } else if (host.platformIsMac()) {
68 | return Paths.get(userHome, "Documents", "Bitwig Studio", "Extensions").toString();
69 |
70 | // Linux
71 | } else if (host.platformIsLinux()) {
72 | return Paths.get(userHome, "Bitwig Studio", "Extensions").toString();
73 | }
74 | // Fallback
75 | return Paths.get(userHome, "Documents", "Bitwig Studio", "Extensions").toString();
76 | }
77 |
78 | /**
79 | * Gets the path to a specific subfolder within the Bitwig Studio extensions directory.
80 | *
81 | * @param subfolder Name of the subfolder to append to the extensions path
82 | * @return String representation of the complete path including the subfolder
83 | */
84 | public static String getExstensionsSubfolderPath(String subfolder) {
85 | return Paths.get(getDefaultExtensionsPath(), subfolder).toString();
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Rock.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Modern Rock (Cue Markers)"
2 | Description: "Generate Cue Markers for a Modern Rock Track."
3 | Author: "Centomila"
4 | Bpm (120)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 | Wait (200)
9 |
10 | // Start with atmospheric intro
11 | jump_to_beginning_of_arranger_window
12 | Wait (100)
13 | insert_arranger_cue_marker_at_play_position
14 | CueMarkerName (1, "Ambient Intro")
15 |
16 | // 4-bar ambient intro
17 | jump_to_beginning_of_next_bar
18 | jump_to_beginning_of_next_bar
19 | jump_to_beginning_of_next_bar
20 | jump_to_beginning_of_next_bar
21 | Wait (100)
22 | insert_arranger_cue_marker_at_play_position
23 | CueMarkerName (2, "Main Intro")
24 |
25 | // 8-bar main intro with basic instruments
26 | jump_forward_8_bars
27 | Wait (100)
28 | insert_arranger_cue_marker_at_play_position
29 | CueMarkerName (3, "Verse 1")
30 |
31 | // 8-bar first verse
32 | jump_forward_8_bars
33 | Wait (100)
34 | insert_arranger_cue_marker_at_play_position
35 | CueMarkerName (4, "Pre-Chorus")
36 |
37 | // 4-bar pre-chorus
38 | jump_to_beginning_of_next_bar
39 | jump_to_beginning_of_next_bar
40 | jump_to_beginning_of_next_bar
41 | jump_to_beginning_of_next_bar
42 | Wait (100)
43 | insert_arranger_cue_marker_at_play_position
44 | CueMarkerName (5, "Chorus 1")
45 |
46 | // 8-bar powerful first chorus
47 | jump_forward_8_bars
48 | Wait (100)
49 | insert_arranger_cue_marker_at_play_position
50 | CueMarkerName (6, "Transition")
51 |
52 | // 4-bar transition
53 | jump_to_beginning_of_next_bar
54 | jump_to_beginning_of_next_bar
55 | jump_to_beginning_of_next_bar
56 | jump_to_beginning_of_next_bar
57 | Wait (100)
58 | insert_arranger_cue_marker_at_play_position
59 | CueMarkerName (7, "Verse 2")
60 |
61 | // 8-bar second verse (often with added elements)
62 | jump_forward_8_bars
63 | Wait (100)
64 | insert_arranger_cue_marker_at_play_position
65 | CueMarkerName (8, "Pre-Chorus 2")
66 |
67 | // 4-bar pre-chorus
68 | jump_to_beginning_of_next_bar
69 | jump_to_beginning_of_next_bar
70 | jump_to_beginning_of_next_bar
71 | jump_to_beginning_of_next_bar
72 | Wait (100)
73 | insert_arranger_cue_marker_at_play_position
74 | CueMarkerName (9, "Chorus 2")
75 |
76 | // 8-bar second chorus
77 | jump_forward_8_bars
78 | Wait (100)
79 | insert_arranger_cue_marker_at_play_position
80 | CueMarkerName (10, "Bridge")
81 |
82 | // 8-bar dynamic bridge section
83 | jump_forward_8_bars
84 | Wait (100)
85 | insert_arranger_cue_marker_at_play_position
86 | CueMarkerName (11, "Breakdown")
87 |
88 | // 4-bar breakdown/quiet section
89 | jump_to_beginning_of_next_bar
90 | jump_to_beginning_of_next_bar
91 | jump_to_beginning_of_next_bar
92 | jump_to_beginning_of_next_bar
93 | Wait (100)
94 | insert_arranger_cue_marker_at_play_position
95 | CueMarkerName (12, "Guitar Solo")
96 |
97 | // 8-bar guitar solo
98 | jump_forward_8_bars
99 | Wait (100)
100 | insert_arranger_cue_marker_at_play_position
101 | CueMarkerName (13, "Build-Up")
102 |
103 | // 4-bar build-up to final chorus
104 | jump_to_beginning_of_next_bar
105 | jump_to_beginning_of_next_bar
106 | jump_to_beginning_of_next_bar
107 | jump_to_beginning_of_next_bar
108 | Wait (100)
109 | insert_arranger_cue_marker_at_play_position
110 | CueMarkerName (14, "Final Chorus")
111 |
112 | // 8-bar extended final chorus
113 | jump_forward_8_bars
114 | Wait (100)
115 | insert_arranger_cue_marker_at_play_position
116 | CueMarkerName (15, "Extended Chorus")
117 |
118 | // 8-bar extended chorus variation
119 | jump_forward_8_bars
120 | Wait (100)
121 | insert_arranger_cue_marker_at_play_position
122 | CueMarkerName (16, "Outro")
123 |
124 | // 4-bar outro
125 | jump_to_beginning_of_next_bar
126 | jump_to_beginning_of_next_bar
127 | jump_to_beginning_of_next_bar
128 | jump_to_beginning_of_next_bar
129 |
130 | Message ("Modern Rock Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Minimal Techno Extended Mix.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Minimal Techno Extended Mix"
2 | Description: "Cue Markers for a Minimal Techno extended mix."
3 | Author: "Centomila"
4 | Bpm (130)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // 1 - Silent intro for DJ mixing
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "DJ Intro - Silent")
14 |
15 | // 2 - Initial minimal elements
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Textural Elements")
20 |
21 | // 3 - First percussion elements
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Minimal Percussion")
26 |
27 | // 4 - Basic rhythm pattern starts
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements - Basic Rhythm")
32 |
33 | // 5 - Kick drum enters
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Main Elements - Kick Added")
38 |
39 | // 6 - Groove development
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (6, "Main Elements - Full Groove")
44 |
45 | // 7 - First subtle change
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (7, "Variation 1 - Subtle Change")
50 |
51 | // 8 - First main section
52 | jump_forward_8_bars
53 | Wait (100)
54 | insert_arranger_cue_marker_at_play_position
55 | CueMarkerName (8, "Main Section 1 - Added Bass Elements")
56 |
57 | // 9 - First minimal breakdown
58 | jump_forward_8_bars
59 | Wait (100)
60 | insert_arranger_cue_marker_at_play_position
61 | CueMarkerName (9, "Minimal Breakdown - Kick Removed")
62 |
63 | // 10 - Percussion focus
64 | jump_forward_8_bars
65 | Wait (100)
66 | insert_arranger_cue_marker_at_play_position
67 | CueMarkerName (10, "Build-Up - Percussion Focus")
68 |
69 | // 11 - Main groove returns with variations
70 | jump_forward_8_bars
71 | Wait (100)
72 | insert_arranger_cue_marker_at_play_position
73 | CueMarkerName (11, "Main Section 2 - Kick Returns")
74 |
75 | // 12 - Main section intensifies
76 | jump_forward_8_bars
77 | Wait (100)
78 | insert_arranger_cue_marker_at_play_position
79 | CueMarkerName (12, "Main Section 2 - Added Elements")
80 |
81 | // 13 - Second breakdown with atmospherics
82 | jump_forward_8_bars
83 | Wait (100)
84 | insert_arranger_cue_marker_at_play_position
85 | CueMarkerName (13, "Main Breakdown - Sparse Elements")
86 |
87 | // 14 - Main tension build
88 | jump_forward_8_bars
89 | Wait (100)
90 | insert_arranger_cue_marker_at_play_position
91 | CueMarkerName (14, "Main Build-Up - Rising Tension")
92 |
93 | // 15 - Peak energy section
94 | jump_forward_8_bars
95 | Wait (100)
96 | insert_arranger_cue_marker_at_play_position
97 | CueMarkerName (15, "Peak Section - All Elements")
98 |
99 | // 16 - Sustained groove section
100 | jump_forward_8_bars
101 | Wait (100)
102 | insert_arranger_cue_marker_at_play_position
103 | CueMarkerName (16, "Main Section 3 - Groove Focus")
104 |
105 | // 17 - Beginning of outro
106 | jump_forward_8_bars
107 | Wait (100)
108 | insert_arranger_cue_marker_at_play_position
109 | CueMarkerName (17, "Outro - Element Reduction")
110 |
111 | // 18 - DJ-friendly outro
112 | jump_forward_8_bars
113 | Wait (100)
114 | insert_arranger_cue_marker_at_play_position
115 | CueMarkerName (18, "DJ Outro - Percussion Only")
116 |
117 | // 19 - Final elements
118 | jump_forward_8_bars
119 | Wait (100)
120 | insert_arranger_cue_marker_at_play_position
121 | CueMarkerName (19, "Track End - Final Elements")
122 |
123 | Message ("Minimal Techno Extended Mix Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Melodic Techno Original Mix.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Melodic Techno Original Mix"
2 | Description: "Cue Markers for a Melodic Techno extended mix."
3 | Author: "Centomila"
4 | Bpm (124)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // 1 - DJ-friendly intro
10 | jump_to_beginning_of_arranger_window
11 | Wait (200)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "Intro - Ambient Pads & Textures")
14 |
15 | // 2 - Basic percussion elements begin
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Percussion Layer Added")
20 |
21 | // 3 - Bassline enters
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Sub Bass & Percussion")
26 |
27 | // 4 - Main kick drum enters
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements - Kick Drum Enters")
32 |
33 | // 5 - Hi-hats and fuller groove develops
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Main Elements - Hi-Hats & Full Rhythm")
38 |
39 | // 6 - First synth elements added
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (6, "Main Elements - Synth Arpeggios Added")
44 |
45 | // 7 - First breakdown begins
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (7, "First Break - Kick Removed, Pads & FX")
50 |
51 | // 8 - Building back elements with filter sweeps
52 | jump_forward_8_bars
53 | Wait (100)
54 | jump_to_beginning_of_next_bar
55 | insert_arranger_cue_marker_at_play_position
56 | CueMarkerName (8, "Build-Up - Filter Sweeps & Rising Tension")
57 |
58 | // 9 - First main drop with all elements
59 | jump_forward_8_bars
60 | Wait (100)
61 | jump_to_beginning_of_next_bar
62 | insert_arranger_cue_marker_at_play_position
63 | CueMarkerName (9, "Drop 1 - Full Groove & Energy")
64 |
65 | // 10 - Melodic section develops further
66 | jump_forward_8_bars
67 | Wait (100)
68 | insert_arranger_cue_marker_at_play_position
69 | CueMarkerName (10, "Main Section - Lead Melody Introduced")
70 |
71 | // 11 - Main breakdown begins
72 | jump_forward_8_bars
73 | Wait (100)
74 | insert_arranger_cue_marker_at_play_position
75 | CueMarkerName (11, "Main Breakdown - Percussion Removed")
76 |
77 | // 12 - Rising tension with FX and build elements
78 | jump_forward_8_bars
79 | Wait (100)
80 | jump_to_beginning_of_next_bar
81 | insert_arranger_cue_marker_at_play_position
82 | CueMarkerName (12, "Main Build-Up - Risers & Tension Elements")
83 |
84 | // 13 - Main peak drop section
85 | jump_forward_8_bars
86 | Wait (100)
87 | jump_to_beginning_of_next_bar
88 | insert_arranger_cue_marker_at_play_position
89 | CueMarkerName (13, "Main Drop - Peak Energy & Full Mix")
90 |
91 | // 14 - Variation with focus on bass elements
92 | jump_forward_8_bars
93 | Wait (100)
94 | insert_arranger_cue_marker_at_play_position
95 | CueMarkerName (14, "Main Drop Variation - Bass Focus")
96 |
97 | // 15 - Beginning of outro elements removal
98 | jump_forward_8_bars
99 | Wait (100)
100 | insert_arranger_cue_marker_at_play_position
101 | CueMarkerName (15, "Outro Part 1 - Main Elements Fading")
102 |
103 | // 16 - DJ-friendly outro section
104 | jump_forward_8_bars
105 | Wait (100)
106 | jump_to_beginning_of_next_bar
107 | insert_arranger_cue_marker_at_play_position
108 | CueMarkerName (16, "Outro Part 2 - Only Pads & Atmosphere")
109 |
110 | // 17 - Fade to silence
111 | jump_forward_8_bars
112 | Wait (100)
113 | insert_arranger_cue_marker_at_play_position
114 | CueMarkerName (17, "Track End - Final Reverb Tails")
115 |
116 | Message ("Melodic Techno Original Mix Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/macro/commands/MacroCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.macro.commands;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.macro.MacroExecutor;
5 | import com.centomila.macro.processor.MacroProcessor;
6 | import com.centomila.macro.state.BitwigStateProvider;
7 | import com.centomila.macro.state.DefaultBitwigStateProvider;
8 | import com.centomila.utils.PopupUtils;
9 | import com.centomila.utils.commands.BaseCommand;
10 |
11 | import java.io.IOException;
12 | import java.nio.file.Files;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 | import java.util.List;
16 |
17 | /**
18 | * Command for executing a macro file which can contain loops and variable assignments.
19 | */
20 | public class MacroCommand extends BaseCommand {
21 | @Override
22 | public void execute(String[] params, BitwigBuddyExtension extension) {
23 | if (!validateMinParamCount(params, 1, extension)) {
24 | return;
25 | }
26 |
27 | String macroName = params[0];
28 | String macrosFolder = extension.getMacrosFolder();
29 | Path macroPath = Paths.get(macrosFolder, macroName + ".txt");
30 |
31 | try {
32 | if (!Files.exists(macroPath)) {
33 | reportError("Macro file not found: " + macroPath, extension);
34 | return;
35 | }
36 |
37 | List macroLines = Files.readAllLines(macroPath);
38 |
39 | // Process loops and variables
40 | // Create a BitwigStateProvider for the macro processor
41 | BitwigStateProvider stateProvider = new DefaultBitwigStateProvider(extension);
42 | MacroProcessor macroProcessor = new MacroProcessor(stateProvider);
43 |
44 | // Enable debug if a debug parameter is passed
45 | if (params.length > 1 && params[1].equalsIgnoreCase("debug")) {
46 | macroProcessor.setDebug(true);
47 | extension.getHost().println("Debug mode enabled for macro processing");
48 | }
49 |
50 | List processedLines;
51 | try {
52 | processedLines = macroProcessor.processCommands(macroLines);
53 | } catch (RuntimeException e) {
54 | reportError("Error parsing macro: " + e.getMessage(), extension);
55 |
56 | // Print the lines for debugging
57 | extension.getHost().println("Macro content:");
58 | for (int i = 0; i < macroLines.size(); i++) {
59 | extension.getHost().println(i + ": " + macroLines.get(i));
60 | }
61 | return;
62 | }
63 |
64 | // Execute each processed line
65 | for (String line : processedLines) {
66 | line = line.trim();
67 | // Skip empty lines, comments, variable definitions and loop closing braces
68 | if (!line.isEmpty() && !line.startsWith("//") &&
69 | !line.startsWith("var ") && !line.matches("\\s*\\}\\s*")) {
70 |
71 | // Execute the actual Bitwig command
72 | boolean success = MacroExecutor.executeCommand(line, extension);
73 |
74 | if (!success && !line.trim().startsWith("//")) {
75 | // Only report errors for non-comment lines
76 | reportError("Failed to execute command: " + line, extension);
77 | }
78 | }
79 | }
80 |
81 | PopupUtils.showPopup("Macro executed: " + macroName);
82 |
83 | } catch (IOException e) {
84 | reportError("Error reading macro file: " + e.getMessage(), extension);
85 | } catch (RuntimeException e) {
86 | reportError("Error processing macro: " + e.getMessage(), extension);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Raw Deep Techno Extended Mix.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Raw Deep Techno Extended Mix"
2 | Description: "Cue Markers for a Raw Deep Techno extended mix."
3 | Author: "Centomila"
4 | Bpm (132)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // 1 - Beatless industrial atmosphere
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "Intro - Industrial Atmosphere")
14 |
15 | // 2 - First deep texture elements
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Dark Textures")
20 |
21 | // 3 - Basic percussive elements
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Basic Percussion")
26 |
27 | // 4 - Deep sub bass enters
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements - Sub Bass Added")
32 |
33 | // 5 - Kick drum enters
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Main Elements - Raw Kick Added")
38 |
39 | // 6 - Full drum pattern established
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (6, "Main Elements - Full Drums")
44 |
45 | // 7 - First phase with all elements
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (7, "Main Section 1 - Full Elements")
50 |
51 | // 8 - Metallic percussion focus
52 | jump_forward_8_bars
53 | Wait (100)
54 | insert_arranger_cue_marker_at_play_position
55 | CueMarkerName (8, "Main Section 1 - Metallic Percussion")
56 |
57 | // 9 - First dark breakdown
58 | jump_forward_8_bars
59 | Wait (100)
60 | insert_arranger_cue_marker_at_play_position
61 | CueMarkerName (9, "First Breakdown - Raw Textures")
62 |
63 | // 10 - First tension build
64 | jump_forward_8_bars
65 | Wait (100)
66 | insert_arranger_cue_marker_at_play_position
67 | CueMarkerName (10, "Build-Up 1 - Industrial Elements")
68 |
69 | // 11 - Main drop section
70 | jump_forward_8_bars
71 | Wait (100)
72 | insert_arranger_cue_marker_at_play_position
73 | CueMarkerName (11, "Main Section 2 - Hard Drop")
74 |
75 | // 12 - Sustained groove with acid elements
76 | jump_forward_8_bars
77 | Wait (100)
78 | insert_arranger_cue_marker_at_play_position
79 | CueMarkerName (12, "Main Section 2 - Acid Elements")
80 |
81 | // 13 - Second main section
82 | jump_forward_8_bars
83 | Wait (100)
84 | insert_arranger_cue_marker_at_play_position
85 | CueMarkerName (13, "Main Section 2 - Full Energy")
86 |
87 | // 14 - Main deep breakdown
88 | jump_forward_8_bars
89 | Wait (100)
90 | insert_arranger_cue_marker_at_play_position
91 | CueMarkerName (14, "Main Breakdown - Deep Atmosphere")
92 |
93 | // 15 - Main tension build
94 | jump_forward_8_bars
95 | Wait (100)
96 | insert_arranger_cue_marker_at_play_position
97 | CueMarkerName (15, "Main Build-Up - Dark Risers")
98 |
99 | // 16 - Peak energy section
100 | jump_forward_8_bars
101 | Wait (100)
102 | insert_arranger_cue_marker_at_play_position
103 | CueMarkerName (16, "Peak Section - Maximum Impact")
104 |
105 | // 17 - Sustained energy with variations
106 | jump_forward_8_bars
107 | Wait (100)
108 | insert_arranger_cue_marker_at_play_position
109 | CueMarkerName (17, "Peak Section - Rhythm Variations")
110 |
111 | // 18 - Beginning of outro
112 | jump_forward_8_bars
113 | Wait (100)
114 | insert_arranger_cue_marker_at_play_position
115 | CueMarkerName (18, "Outro - Element Reduction")
116 |
117 | // 19 - Final percussion
118 | jump_forward_8_bars
119 | Wait (100)
120 | insert_arranger_cue_marker_at_play_position
121 | CueMarkerName (19, "DJ Outro - Raw Percussion")
122 |
123 | // 20 - Final atmospherics
124 | jump_forward_8_bars
125 | Wait (100)
126 | insert_arranger_cue_marker_at_play_position
127 | CueMarkerName (20, "Track End - Dark Atmosphere")
128 |
129 | Message ("Raw Deep Techno Extended Mix Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/MacroCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.macro.MacroExecutor;
5 | import com.centomila.utils.LoopProcessor;
6 | import com.centomila.utils.PopupUtils;
7 | import com.centomila.utils.commands.BaseCommand;
8 |
9 | import java.io.IOException;
10 | import java.nio.file.Files;
11 | import java.nio.file.Path;
12 | import java.nio.file.Paths;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * Command for executing a macro file which can contain loops and variable assignments.
18 | */
19 | public class MacroCommand extends BaseCommand {
20 | @Override
21 | public void execute(String[] params, BitwigBuddyExtension extension) {
22 | if (!validateMinParamCount(params, 1, extension)) {
23 | return;
24 | }
25 |
26 | String macroName = params[0];
27 | String macrosFolder = extension.getMacrosFolder();
28 | Path macroPath = Paths.get(macrosFolder, macroName + ".txt");
29 |
30 | try {
31 | if (!Files.exists(macroPath)) {
32 | reportError("Macro file not found: " + macroPath, extension);
33 | return;
34 | }
35 |
36 | List macroLines = Files.readAllLines(macroPath);
37 |
38 | // Normalize indentation to avoid tab issues
39 | List normalizedLines = new ArrayList<>();
40 | for (String line : macroLines) {
41 | // Convert all whitespace sequences (including tabs) to single spaces
42 | // except for spaces around braces and within expressions
43 | normalizedLines.add(line);
44 | }
45 |
46 | // Process loops and variables
47 | LoopProcessor loopProcessor = new LoopProcessor(extension.getStateProvider());
48 |
49 | // Enable debug if a debug parameter is passed
50 | if (params.length > 1 && params[1].equalsIgnoreCase("debug")) {
51 | loopProcessor.setDebug(true);
52 | extension.getHost().println("Debug mode enabled for macro processing");
53 | }
54 |
55 | List processedLines;
56 | try {
57 | processedLines = loopProcessor.processLoop(normalizedLines);
58 | } catch (RuntimeException e) {
59 | reportError("Error parsing macro: " + e.getMessage(), extension);
60 |
61 | // Print the lines for debugging
62 | extension.getHost().println("Macro content:");
63 | for (int i = 0; i < normalizedLines.size(); i++) {
64 | extension.getHost().println(i + ": " + normalizedLines.get(i));
65 | }
66 | return;
67 | }
68 |
69 | // Execute each processed line
70 | for (String line : processedLines) {
71 | line = line.trim();
72 | // Skip empty lines, comments, variable definitions and loop closing braces
73 | if (!line.isEmpty() && !line.startsWith("//") &&
74 | !line.startsWith("var ") && !line.matches("\\s*\\}\\s*")) {
75 |
76 | // Execute the actual Bitwig command
77 | boolean success = MacroExecutor.executeCommand(line, extension);
78 |
79 | if (!success && !line.trim().startsWith("//")) {
80 | // Only report errors for non-comment lines
81 | reportError("Failed to execute command: " + line, extension);
82 | }
83 | }
84 | }
85 |
86 | PopupUtils.showPopup("Macro executed: " + macroName);
87 |
88 | } catch (IOException e) {
89 | reportError("Error reading macro file: " + e.getMessage(), extension);
90 | } catch (RuntimeException e) {
91 | reportError("Error processing macro: " + e.getMessage(), extension);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Tech House Extended Mix.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Tech House Extended Mix"
2 | Description: "Cue Markers for a Tech House extended mix."
3 | Author: "Centomila"
4 | Bpm (130)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // 1 - DJ-friendly intro
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "DJ Intro - Minimal Loop")
14 |
15 | // 2 - First percussion elements
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Percussion & FX")
20 |
21 | // 3 - Bass elements begin
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Bass Elements")
26 |
27 | // 4 - Kick drum enters
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements - Kick Added")
32 |
33 | // 5 - Hi-hats and rhythm development
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Main Elements - Hi-Hats & Rhythm")
38 |
39 | // 6 - Full groove established
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (6, "Main Elements - Full Groove")
44 |
45 | // 7 - First vocal/sample elements
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (7, "Main Section 1 - Vocal Samples Added")
50 |
51 | // 8 - First main section evolves
52 | jump_forward_8_bars
53 | Wait (100)
54 | insert_arranger_cue_marker_at_play_position
55 | CueMarkerName (8, "Main Section 1 - Full Energy")
56 |
57 | // 9 - First breakdown (house influenced)
58 | jump_forward_8_bars
59 | Wait (100)
60 | insert_arranger_cue_marker_at_play_position
61 | CueMarkerName (9, "First Breakdown - House Elements")
62 |
63 | // 10 - First tension build
64 | jump_forward_8_bars
65 | Wait (100)
66 | insert_arranger_cue_marker_at_play_position
67 | CueMarkerName (10, "Build-Up 1 - Rising Tension")
68 |
69 | // 11 - First drop with rolling bassline
70 | jump_forward_8_bars
71 | Wait (100)
72 | insert_arranger_cue_marker_at_play_position
73 | CueMarkerName (11, "Drop 1 - Rolling Bass")
74 |
75 | // 12 - Main groove continues with variations
76 | jump_forward_8_bars
77 | Wait (100)
78 | insert_arranger_cue_marker_at_play_position
79 | CueMarkerName (12, "Main Section 2 - Groove Variations")
80 |
81 | // 13 - Additional vocal/sample elements
82 | jump_forward_8_bars
83 | Wait (100)
84 | insert_arranger_cue_marker_at_play_position
85 | CueMarkerName (13, "Main Section 2 - Added Hooks")
86 |
87 | // 14 - Main breakdown with filter sweeps
88 | jump_forward_8_bars
89 | Wait (100)
90 | insert_arranger_cue_marker_at_play_position
91 | CueMarkerName (14, "Main Breakdown - Filter Sweeps")
92 |
93 | // 15 - Main build-up section
94 | jump_forward_8_bars
95 | Wait (100)
96 | insert_arranger_cue_marker_at_play_position
97 | CueMarkerName (15, "Main Build-Up - Rising Elements")
98 |
99 | // 16 - Peak energy section with full mix
100 | jump_forward_8_bars
101 | Wait (100)
102 | insert_arranger_cue_marker_at_play_position
103 | CueMarkerName (16, "Main Drop - Full Energy")
104 |
105 | // 17 - Peak section with tech elements
106 | jump_forward_8_bars
107 | Wait (100)
108 | insert_arranger_cue_marker_at_play_position
109 | CueMarkerName (17, "Main Drop - Tech Focus")
110 |
111 | // 18 - Sustained groove with house elements
112 | jump_forward_8_bars
113 | Wait (100)
114 | insert_arranger_cue_marker_at_play_position
115 | CueMarkerName (18, "Main Drop - House Elements")
116 |
117 | // 19 - Beginning of outro section
118 | jump_forward_8_bars
119 | Wait (100)
120 | insert_arranger_cue_marker_at_play_position
121 | CueMarkerName (19, "Outro - Element Reduction")
122 |
123 | // 20 - DJ-friendly outro section
124 | jump_forward_8_bars
125 | Wait (100)
126 | insert_arranger_cue_marker_at_play_position
127 | CueMarkerName (20, "DJ Outro - Rhythm & Bass")
128 |
129 | // 21 - Final percussion elements
130 | jump_forward_8_bars
131 | Wait (100)
132 | insert_arranger_cue_marker_at_play_position
133 | CueMarkerName (21, "Track End - Final Elements")
134 |
135 | Message ("Tech House Extended Mix Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Arrangement/Arrangement - Hypnotic Techno Extended Mix.txt:
--------------------------------------------------------------------------------
1 | Macro: "Arrangement - Hypnotic Techno Extended Mix"
2 | Description: "Cue Markers for a Hypnotic Techno extended mix."
3 | Author: "Centomila"
4 | Bpm (135)
5 | Time Signature ("4/4")
6 |
7 | DeleteAllCueMarkers
8 |
9 | // 1 - Atmospheric hypnotic intro
10 | jump_to_beginning_of_arranger_window
11 | Wait (100)
12 | insert_arranger_cue_marker_at_play_position
13 | CueMarkerName (1, "Intro - Ethereal Atmosphere")
14 |
15 | // 2 - First rhythmic elements
16 | jump_forward_8_bars
17 | Wait (100)
18 | insert_arranger_cue_marker_at_play_position
19 | CueMarkerName (2, "Intro - Rhythmic Patterns")
20 |
21 | // 3 - Initial repetitive elements
22 | jump_forward_8_bars
23 | Wait (100)
24 | insert_arranger_cue_marker_at_play_position
25 | CueMarkerName (3, "Intro - Repetitive Synth Motif")
26 |
27 | // 4 - First percussion additions
28 | jump_forward_8_bars
29 | Wait (100)
30 | insert_arranger_cue_marker_at_play_position
31 | CueMarkerName (4, "Main Elements - Basic Percussion")
32 |
33 | // 5 - Main kick enters
34 | jump_forward_8_bars
35 | Wait (100)
36 | insert_arranger_cue_marker_at_play_position
37 | CueMarkerName (5, "Main Elements - Kick Added")
38 |
39 | // 6 - First development of main pattern
40 | jump_forward_8_bars
41 | Wait (100)
42 | insert_arranger_cue_marker_at_play_position
43 | CueMarkerName (6, "Main Elements - Pattern Development")
44 |
45 | // 7 - First subtle evolution
46 | jump_forward_8_bars
47 | Wait (100)
48 | insert_arranger_cue_marker_at_play_position
49 | CueMarkerName (7, "Main Section 1 - Subtle Evolution")
50 |
51 | // 8 - Bass pattern intensifies
52 | jump_forward_8_bars
53 | Wait (100)
54 | insert_arranger_cue_marker_at_play_position
55 | CueMarkerName (8, "Main Section 1 - Bass Focus")
56 |
57 | // 9 - Main repetitive section
58 | jump_forward_8_bars
59 | Wait (100)
60 | insert_arranger_cue_marker_at_play_position
61 | CueMarkerName (9, "Main Section 1 - Hypnotic State")
62 |
63 | // 10 - First variation with acid elements
64 | jump_forward_8_bars
65 | Wait (100)
66 | insert_arranger_cue_marker_at_play_position
67 | CueMarkerName (10, "Variation 1 - Acid Elements")
68 |
69 | // 11 - First minimalist breakdown
70 | jump_forward_8_bars
71 | Wait (100)
72 | insert_arranger_cue_marker_at_play_position
73 | CueMarkerName (11, "First Breakdown - Reduced Elements")
74 |
75 | // 12 - First tension build
76 | jump_forward_8_bars
77 | Wait (100)
78 | insert_arranger_cue_marker_at_play_position
79 | CueMarkerName (12, "Build-Up 1 - Rising Repetition")
80 |
81 | // 13 - Second main hypnotic section
82 | jump_forward_8_bars
83 | Wait (100)
84 | insert_arranger_cue_marker_at_play_position
85 | CueMarkerName (13, "Main Section 2 - Full Hypnotic Elements")
86 |
87 | // 14 - Sustained groove with modulation
88 | jump_forward_8_bars
89 | Wait (100)
90 | insert_arranger_cue_marker_at_play_position
91 | CueMarkerName (14, "Main Section 2 - Pattern Modulation")
92 |
93 | // 15 - Main breakdown with focal synth
94 | jump_forward_8_bars
95 | Wait (100)
96 | insert_arranger_cue_marker_at_play_position
97 | CueMarkerName (15, "Main Breakdown - Focus Synth Element")
98 |
99 | // 16 - Main tension build
100 | jump_forward_8_bars
101 | Wait (100)
102 | insert_arranger_cue_marker_at_play_position
103 | CueMarkerName (16, "Main Build-Up - Rhythmic Tension")
104 |
105 | // 17 - Peak energy section
106 | jump_forward_8_bars
107 | Wait (100)
108 | insert_arranger_cue_marker_at_play_position
109 | CueMarkerName (17, "Peak Section - Maximum Hypnotic State")
110 |
111 | // 18 - Sustained energy with subtle variations
112 | jump_forward_8_bars
113 | Wait (100)
114 | insert_arranger_cue_marker_at_play_position
115 | CueMarkerName (18, "Peak Section - Subtle Evolving Variations")
116 |
117 | // 19 - Beginning of outro elements reduction
118 | jump_forward_8_bars
119 | Wait (100)
120 | insert_arranger_cue_marker_at_play_position
121 | CueMarkerName (19, "Outro - Gradual Reduction")
122 |
123 | // 20 - Final pattern loop
124 | jump_forward_8_bars
125 | Wait (100)
126 | insert_arranger_cue_marker_at_play_position
127 | CueMarkerName (20, "DJ Outro - Minimal Loop")
128 |
129 | // 21 - Final atmospheric elements
130 | jump_forward_8_bars
131 | Wait (100)
132 | insert_arranger_cue_marker_at_play_position
133 | CueMarkerName (21, "Track End - Ethereal Fade")
134 |
135 | Message ("Hypnotic Techno Extended Mix Arrangement Complete")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/MessageCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.macro.state.BitwigStateProvider;
5 | import com.centomila.macro.state.DefaultBitwigStateProvider;
6 | import com.centomila.utils.PopupUtils;
7 | import com.centomila.utils.commands.BaseCommand;
8 |
9 | import java.util.regex.Matcher;
10 | import java.util.regex.Pattern;
11 |
12 | /**
13 | * Shows a popup message to the user.
14 | * Supports variable and function expression interpolation.
15 | */
16 | public class MessageCommand extends BaseCommand {
17 | // Match function calls in both formats: direct and wrapped in ${}
18 | private static final Pattern FUNCTION_CALL_DIRECT = Pattern.compile("([a-zA-Z_][a-zA-Z0-9_]*)\\(\\)");
19 | private static final Pattern EXPRESSION_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");
20 |
21 | @Override
22 | public void execute(String[] params, BitwigBuddyExtension extension) {
23 | if (!validateMinParamCount(params, 1, extension)) {
24 | return;
25 | }
26 |
27 | // Join all parameters with spaces to handle multi-part messages
28 | String message = String.join(" ", params);
29 |
30 | // Process any expressions within the message
31 | message = processExpressions(message, extension);
32 |
33 | // Show the message
34 | PopupUtils.showPopup(message);
35 | }
36 |
37 | /**
38 | * Process expressions in ${...} format and direct function calls
39 | */
40 | private String processExpressions(String message, BitwigBuddyExtension extension) {
41 | BitwigStateProvider stateProvider = new DefaultBitwigStateProvider(extension);
42 |
43 | // First process wrapped expressions with ${...} syntax
44 | message = processWrappedExpressions(message, stateProvider);
45 |
46 | // Then process direct function calls like getCurrentTrackName()
47 | message = processDirectFunctionCalls(message, stateProvider);
48 |
49 | return message;
50 | }
51 |
52 | /**
53 | * Process expressions wrapped in ${...}
54 | */
55 | private String processWrappedExpressions(String message, BitwigStateProvider stateProvider) {
56 | // If no expressions are present, return the original message
57 | if (!message.contains("${")) {
58 | return message;
59 | }
60 |
61 | // Find and replace all expressions
62 | Matcher matcher = EXPRESSION_PATTERN.matcher(message);
63 | StringBuffer result = new StringBuffer();
64 |
65 | while (matcher.find()) {
66 | String expression = matcher.group(1);
67 | String replacement;
68 |
69 | // Check if the expression is a function call
70 | Matcher funcMatcher = FUNCTION_CALL_DIRECT.matcher(expression);
71 | if (funcMatcher.matches()) {
72 | String functionName = funcMatcher.group(1);
73 | replacement = executeFunctionCall(functionName, stateProvider);
74 | } else {
75 | // For other expressions, just use as is for now
76 | replacement = expression;
77 | }
78 |
79 | // Replace the expression with its result
80 | matcher.appendReplacement(result, replacement.replace("$", "\\$"));
81 | }
82 | matcher.appendTail(result);
83 |
84 | return result.toString();
85 | }
86 |
87 | /**
88 | * Process direct function calls not wrapped in ${}
89 | */
90 | private String processDirectFunctionCalls(String message, BitwigStateProvider stateProvider) {
91 | Matcher matcher = FUNCTION_CALL_DIRECT.matcher(message);
92 | StringBuffer result = new StringBuffer();
93 |
94 | while (matcher.find()) {
95 | String functionName = matcher.group(1);
96 | String replacement = executeFunctionCall(functionName, stateProvider);
97 | matcher.appendReplacement(result, replacement.replace("$", "\\$"));
98 | }
99 | matcher.appendTail(result);
100 |
101 | return result.toString();
102 | }
103 |
104 | /**
105 | * Execute a function call and return its result as a string
106 | */
107 | private String executeFunctionCall(String functionName, BitwigStateProvider stateProvider) {
108 | if (stateProvider.supportsMethod(functionName)) {
109 | Object value = stateProvider.callMethod(functionName);
110 | return value != null ? value.toString() : "null";
111 | }
112 | return "Function not supported: " + functionName;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/utility/ConsoleCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.utility;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.macro.state.BitwigStateProvider;
5 | import com.centomila.macro.state.DefaultBitwigStateProvider;
6 | import com.centomila.utils.commands.BaseCommand;
7 |
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | /**
12 | * Writes a message to the Bitwig Studio console.
13 | * Supports variable and function expression interpolation.
14 | */
15 | public class ConsoleCommand extends BaseCommand {
16 | // Match function calls in both formats: direct and wrapped in ${}
17 | private static final Pattern FUNCTION_CALL_DIRECT = Pattern.compile("([a-zA-Z_][a-zA-Z0-9_]*)\\(\\)");
18 | private static final Pattern EXPRESSION_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");
19 |
20 | @Override
21 | public void execute(String[] params, BitwigBuddyExtension extension) {
22 | if (!validateMinParamCount(params, 1, extension)) {
23 | return;
24 | }
25 |
26 | // Join all parameters with spaces to handle multi-part messages
27 | String message = String.join(" ", params);
28 |
29 | // Process any expressions within the message
30 | message = processExpressions(message, extension);
31 |
32 | // Write the message to the Bitwig console
33 | extension.getHost().println("[BeatBuddy] " + message);
34 | }
35 |
36 | /**
37 | * Process expressions in ${...} format and direct function calls
38 | */
39 | private String processExpressions(String message, BitwigBuddyExtension extension) {
40 | BitwigStateProvider stateProvider = new DefaultBitwigStateProvider(extension);
41 |
42 | // First process wrapped expressions with ${...} syntax
43 | message = processWrappedExpressions(message, stateProvider);
44 |
45 | // Then process direct function calls like getCurrentTrackName()
46 | message = processDirectFunctionCalls(message, stateProvider);
47 |
48 | return message;
49 | }
50 |
51 | /**
52 | * Process expressions wrapped in ${...}
53 | */
54 | private String processWrappedExpressions(String message, BitwigStateProvider stateProvider) {
55 | // If no expressions are present, return the original message
56 | if (!message.contains("${")) {
57 | return message;
58 | }
59 |
60 | // Find and replace all expressions
61 | Matcher matcher = EXPRESSION_PATTERN.matcher(message);
62 | StringBuffer result = new StringBuffer();
63 |
64 | while (matcher.find()) {
65 | String expression = matcher.group(1);
66 | String replacement;
67 |
68 | // Check if the expression is a function call
69 | Matcher funcMatcher = FUNCTION_CALL_DIRECT.matcher(expression);
70 | if (funcMatcher.matches()) {
71 | String functionName = funcMatcher.group(1);
72 | replacement = executeFunctionCall(functionName, stateProvider);
73 | } else {
74 | // For other expressions, just use as is for now
75 | replacement = expression;
76 | }
77 |
78 | // Replace the expression with its result
79 | matcher.appendReplacement(result, replacement.replace("$", "\\$"));
80 | }
81 | matcher.appendTail(result);
82 |
83 | return result.toString();
84 | }
85 |
86 | /**
87 | * Process direct function calls not wrapped in ${}
88 | */
89 | private String processDirectFunctionCalls(String message, BitwigStateProvider stateProvider) {
90 | Matcher matcher = FUNCTION_CALL_DIRECT.matcher(message);
91 | StringBuffer result = new StringBuffer();
92 |
93 | while (matcher.find()) {
94 | String functionName = matcher.group(1);
95 | String replacement = executeFunctionCall(functionName, stateProvider);
96 | matcher.appendReplacement(result, replacement.replace("$", "\\$"));
97 | }
98 | matcher.appendTail(result);
99 |
100 | return result.toString();
101 | }
102 |
103 | /**
104 | * Execute a function call and return its result as a string
105 | */
106 | private String executeFunctionCall(String functionName, BitwigStateProvider stateProvider) {
107 | if (stateProvider.supportsMethod(functionName)) {
108 | Object value = stateProvider.callMethod(functionName);
109 | return value != null ? value.toString() : "null";
110 | }
111 | return "Function not supported: " + functionName;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/utils/commands/clip/ClipCreateCommand.java:
--------------------------------------------------------------------------------
1 | package com.centomila.utils.commands.clip;
2 |
3 | import com.centomila.BitwigBuddyExtension;
4 | import com.centomila.MacroActionSettings;
5 | import com.centomila.ModeSelectSettings;
6 | import com.centomila.utils.commands.BaseCommand;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * Command to create a new clip in the launcher or arranger.
13 | */
14 | public class ClipCreateCommand extends BaseCommand {
15 |
16 | @Override
17 | public void execute(String[] params, BitwigBuddyExtension extension) {
18 | if (!validateMinParamCount(params, 1, extension)) {
19 | return;
20 | }
21 |
22 | // Get current track index
23 | int currentTrack = extension.trackBank.cursorIndex().getAsInt();
24 | if (currentTrack < 0) {
25 | extension.getHost().println("No track selected, using first track (index 0)");
26 | currentTrack = 0;
27 | }
28 |
29 | // Parse parameters
30 | int clipLength = 4; // Default value
31 | int slotIndex;
32 |
33 | try {
34 | // Parse first parameter (slot index) - handle potential floating point values
35 | String slotParam = params[0].trim();
36 | if (slotParam.contains(".")) {
37 | // If it's a floating point, round to nearest integer
38 | double slotDouble = Double.parseDouble(slotParam);
39 | slotIndex = (int) Math.round(slotDouble);
40 | extension.getHost().println("Rounded slot index from " + slotDouble + " to " + slotIndex);
41 | } else {
42 | slotIndex = Integer.parseInt(slotParam);
43 | }
44 |
45 | // Adjust to 0-based index
46 | slotIndex = slotIndex - 1;
47 |
48 | // Parse second parameter (clip length) if available
49 | if (params.length > 1) {
50 | String lengthParam = params[1].trim();
51 | if (lengthParam.contains(".")) {
52 | // If it's a floating point, round to nearest integer
53 | double lengthDouble = Double.parseDouble(lengthParam);
54 | clipLength = (int) Math.round(lengthDouble);
55 | extension.getHost().println("Rounded clip length from " + lengthDouble + " to " + clipLength);
56 | } else {
57 | clipLength = Integer.parseInt(lengthParam);
58 | }
59 | }
60 | } catch (NumberFormatException e) {
61 | reportError("Invalid parameter format: " + e.getMessage(), extension);
62 | return;
63 | }
64 |
65 | // Execute command based on mode
66 | if (ModeSelectSettings.getCurrentLauncherArrangerToggleString().equals("Arranger")) {
67 | handleArrangerModeClipCreation(extension, clipLength);
68 | } else {
69 | handleLauncherModeClipCreation(extension, currentTrack, slotIndex, clipLength);
70 | }
71 | }
72 |
73 | private void handleArrangerModeClipCreation(BitwigBuddyExtension extension, int clipLength) {
74 | // Schedule the actions sequentially
75 | extension.application.setPanelLayout("ARRANGE");
76 | extension.arrangerClip.clipLauncherSlot().showInEditor();
77 |
78 | List actions = new ArrayList<>();
79 | actions.add("select_start_of_selection_range");
80 | for (int i = 0; i < clipLength; i++) {
81 | actions.add("extend_time_selection_range_to_next_step");
82 | }
83 | actions.add("Consolidate");
84 | actions.add("switch_between_event_and_time_selection");
85 |
86 | // Use the scheduler from MacroActionSettings to execute the actions
87 | MacroActionSettings.scheduleCommands(
88 | actions.toArray(new String[0]),
89 | 0,
90 | extension
91 | );
92 | extension.arrangerClip.isLoopEnabled().set(true);
93 | }
94 |
95 | private void handleLauncherModeClipCreation(BitwigBuddyExtension extension, int trackIndex, int slotIndex, int clipLength) {
96 | if (slotIndex >= 0) {
97 | // Delete existing clip if present
98 | extension.trackBank.getItemAt(trackIndex).clipLauncherSlotBank().getItemAt(slotIndex).deleteObject();
99 |
100 | // Create new clip
101 | extension.trackBank.getItemAt(trackIndex).clipLauncherSlotBank()
102 | .createEmptyClip(slotIndex, clipLength);
103 |
104 | // Make track visible
105 | extension.trackBank.getItemAt(trackIndex).makeVisibleInMixer();
106 | extension.trackBank.getItemAt(trackIndex).makeVisibleInArranger();
107 |
108 | extension.getHost().println("Created empty clip with length: " + clipLength);
109 | } else {
110 | extension.getHost().println("No clip slot selected. Please select a clip slot first.");
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/centomila/customPresetsTxt/Macros/Samples/Rainbow.txt:
--------------------------------------------------------------------------------
1 | Macro: "Rainbow Clip"
2 | Descritpion: "Clip Duplicate the selected clip 64 times with rainbow colors"
3 | Author: "Centomila"
4 |
5 | BB Close Panel
6 | Wait (100)
7 | Clip Rename (FF0000 - Red)
8 | Clip Color (FF0000)
9 | Clip Duplicate
10 | Clip Rename (FF1100 - Red)
11 | Clip Color (FF1100)
12 | Clip Duplicate
13 | Clip Rename (FF2200 - Red)
14 | Clip Color (FF2200)
15 | Clip Duplicate
16 | Clip Rename (FF3300 - Red)
17 | Clip Color (FF3300)
18 | Clip Duplicate
19 | Clip Rename (FF4400 - Red)
20 | Clip Color (FF4400)
21 | Clip Duplicate
22 | Clip Rename (FF5500 - Red)
23 | Clip Color (FF5500)
24 | Clip Duplicate
25 | Clip Rename (FF6600 - Orange)
26 | Clip Color (FF6600)
27 | Clip Duplicate
28 | Clip Rename (FF7700 - Orange)
29 | Clip Color (FF7700)
30 | Clip Duplicate
31 | Clip Rename (FF8800 - Orange)
32 | Clip Color (FF8800)
33 | Clip Duplicate
34 | Clip Rename (FF9900 - Orange)
35 | Clip Color (FF9900)
36 | Clip Duplicate
37 | Clip Rename (FFAA00 - Orange)
38 | Clip Color (FFAA00)
39 | Clip Duplicate
40 | Clip Rename (FFBB00 - Orange)
41 | Clip Color (FFBB00)
42 | Clip Duplicate
43 | Clip Rename (FFCC00 - Orange)
44 | Clip Color (FFCC00)
45 | Clip Duplicate
46 | Clip Rename (FFDD00 - Yellow)
47 | Clip Color (FFDD00)
48 | Clip Duplicate
49 | Clip Rename (FFEE00 - Yellow)
50 | Clip Color (FFEE00)
51 | Clip Duplicate
52 | Clip Rename (FFFF00 - Yellow)
53 | Clip Color (FFFF00)
54 | Clip Duplicate
55 | Clip Rename (EEFF00 - Yellow)
56 | Clip Color (EEFF00)
57 | Clip Duplicate
58 | Clip Rename (DDFF00 - Yellow)
59 | Clip Color (DDFF00)
60 | Clip Duplicate
61 | Clip Rename (CCFF00 - Yellow)
62 | Clip Color (CCFF00)
63 | Clip Duplicate
64 | Clip Rename (BBFF00 - Yellow)
65 | Clip Color (BBFF00)
66 | Clip Duplicate
67 | Clip Rename (AAFF00 - Yellow)
68 | Clip Color (AAFF00)
69 | Clip Duplicate
70 | Clip Rename (99FF00 - Green)
71 | Clip Color (99FF00)
72 | Clip Duplicate
73 | Clip Rename (88FF00 - Green)
74 | Clip Color (88FF00)
75 | Clip Duplicate
76 | Clip Rename (77FF00 - Green)
77 | Clip Color (77FF00)
78 | Clip Duplicate
79 | Clip Rename (66FF00 - Green)
80 | Clip Color (66FF00)
81 | Clip Duplicate
82 | Clip Rename (55FF00 - Green)
83 | Clip Color (55FF00)
84 | Clip Duplicate
85 | Clip Rename (44FF00 - Green)
86 | Clip Color (44FF00)
87 | Clip Duplicate
88 | Clip Rename (33FF00 - Green)
89 | Clip Color (33FF00)
90 | Clip Duplicate
91 | Clip Rename (22FF00 - Green)
92 | Clip Color (22FF00)
93 | Clip Duplicate
94 | Clip Rename (11FF00 - Green)
95 | Clip Color (11FF00)
96 | Clip Duplicate
97 | Clip Rename (00FF00 - Green)
98 | Clip Color (00FF00)
99 | Clip Duplicate
100 | Clip Rename (00FF11 - Green)
101 | Clip Color (00FF11)
102 | Clip Duplicate
103 | Clip Rename (00FF22 - Green)
104 | Clip Color (00FF22)
105 | Clip Duplicate
106 | Clip Rename (00FF33 - Green)
107 | Clip Color (00FF33)
108 | Clip Duplicate
109 | Clip Rename (00FF44 - Green)
110 | Clip Color (00FF44)
111 | Clip Duplicate
112 | Clip Rename (00FF55 - Green)
113 | Clip Color (00FF55)
114 | Clip Duplicate
115 | Clip Rename (00FF66 - Green)
116 | Clip Color (00FF66)
117 | Clip Duplicate
118 | Clip Rename (00FF77 - Green)
119 | Clip Color (00FF77)
120 | Clip Duplicate
121 | Clip Rename (00FF88 - Green)
122 | Clip Color (00FF88)
123 | Clip Duplicate
124 | Clip Rename (00FF99 - Green)
125 | Clip Color (00FF99)
126 | Clip Duplicate
127 | Clip Rename (00FFAA - Green)
128 | Clip Color (00FFAA)
129 | Clip Duplicate
130 | Clip Rename (00FFBB - Green)
131 | Clip Color (00FFBB)
132 | Clip Duplicate
133 | Clip Rename (00FFCC - Green)
134 | Clip Color (00FFCC)
135 | Clip Duplicate
136 | Clip Rename (00FFDD - Green)
137 | Clip Color (00FFDD)
138 | Clip Duplicate
139 | Clip Rename (00FFEE - Green)
140 | Clip Color (00FFEE)
141 | Clip Duplicate
142 | Clip Rename (00FFFF - Cyan)
143 | Clip Color (00FFFF)
144 | Clip Duplicate
145 | Clip Rename (00EEFF - Cyan)
146 | Clip Color (00EEFF)
147 | Clip Duplicate
148 | Clip Rename (00DDFF - Cyan)
149 | Clip Color (00DDFF)
150 | Clip Duplicate
151 | Clip Rename (00CCFF - Cyan)
152 | Clip Color (00CCFF)
153 | Clip Duplicate
154 | Clip Rename (00BBFF - Cyan)
155 | Clip Color (00BBFF)
156 | Clip Duplicate
157 | Clip Rename (00AAFF - Cyan)
158 | Clip Color (00AAFF)
159 | Clip Duplicate
160 | Clip Rename (0099FF - Cyan)
161 | Clip Color (0099FF)
162 | Clip Duplicate
163 | Clip Rename (0088FF - Cyan)
164 | Clip Color (0088FF)
165 | Clip Duplicate
166 | Clip Rename (0077FF - Cyan)
167 | Clip Color (0077FF)
168 | Clip Duplicate
169 | Clip Rename (0066FF - Cyan)
170 | Clip Color (0066FF)
171 | Clip Duplicate
172 | Clip Rename (0055FF - Cyan)
173 | Clip Color (0055FF)
174 | Clip Duplicate
175 | Clip Rename (0044FF - Cyan)
176 | Clip Color (0044FF)
177 | Clip Duplicate
178 | Clip Rename (0033FF - Cyan)
179 | Clip Color (0033FF)
180 | Clip Duplicate
181 | Clip Rename (0022FF - Cyan)
182 | Clip Color (0022FF)
183 | Clip Duplicate
184 | Clip Rename (0011FF - Cyan)
185 | Clip Color (0011FF)
186 | Clip Duplicate
187 | Clip Rename (0000FF - Blue)
188 | Clip Color (0000FF)
189 | Clip Duplicate
190 | Clip Rename (1100FF - Blue)
191 | Clip Color (1100FF)
192 | Clip Duplicate
193 | Clip Rename (2200FF - Blue)
194 | Clip Color (2200FF)
195 | Clip Duplicate
196 | Clip Rename (3300FF - Blue)
197 | Clip Color (3300FF)
198 | Clip Duplicate
199 |
200 | Message ("Macro Finished")
--------------------------------------------------------------------------------
/src/main/java/com/centomila/DefaultPatterns.java:
--------------------------------------------------------------------------------
1 | package com.centomila;
2 |
3 | public interface DefaultPatterns {
4 |
5 | final static Pattern[] patterns = {
6 | // --- Various ---
7 | new Pattern("Various: 8th Increasing Velocity", new int[] { 3, 0, 17, 0, 33, 0, 49, 0, 65, 0, 81, 0, 97, 0, 115, 0 }, "C1", "1/16", "1/16", "Straight"),
8 | new Pattern("Various: 16th Increasing Velocity", new int[] { 3, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 115, 127 }, "C1", "1/16", "1/16", "Straight"),
9 | new Pattern("Various: 8th Decreasing Velocity", new int[] { 115, 0, 97, 0, 81, 0, 65, 0, 49, 0, 33, 0, 17, 0, 3, 0 }, "C1", "1/16", "1/16", "Straight"),
10 | new Pattern("Various: 16th Decreasing Velocity", new int[] { 127, 115, 105, 97, 89, 81, 73, 65, 57, 49, 41, 33, 25, 17, 9, 3 }, "C1", "1/16", "1/16", "Straight"),
11 | // --- KICK-ONLY PATTERNS ---
12 | new Pattern("Kick: Four on the Floor", new int[] { 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0 }, "C1", "1/16", "1/16", "Straight"),
13 | new Pattern("Kick: 1 and 3", new int[] { 100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0 }, "C1", "1/16", "1/16", "Straight"),
14 | new Pattern("Kick: Syncopated (1, & of 2, 3)", new int[] { 100, 0, 0, 0, 0, 0, 100, 0, 100, 0, 0, 0, 0, 0, 0, 0 }, "C1", "1/16", "1/16", "Straight"),
15 | new Pattern("Kick: Off-Beats (2 and 4)", new int[] { 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0 }, "C1", "1/16", "1/16", "Straight"),
16 | new Pattern("Kick: Driving 8th Notes", new int[] { 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0 }, "C1", "1/16", "1/16", "Straight"),
17 | // --- SNARE-ONLY PATTERNS ---
18 | new Pattern("Snare: Backbeat 2 and 4", new int[] { 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0 }, "C#1", "1/16", "1/16", "Straight"),
19 | new Pattern("Snare: Only on Beat 2", new int[] { 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, "C#1", "1/16", "1/16", "Straight"),
20 | new Pattern("Snare: Half-Time (3)", new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0 }, "C#1", "1/16", "1/16", "Straight"),
21 | new Pattern("Snare: 16th Ghost Notes", new int[] { 20, 0, 20, 0, 100, 0, 20, 0, 20, 0, 20, 0, 100, 0, 20, 0 }, "C#1", "1/16", "1/16", "Straight"),
22 | new Pattern("Snare: 16th Machine Gun", new int[] { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 }, "C#1", "1/16", "1/16", "Straight"),
23 | // --- HI-HAT-ONLY PATTERNS ---
24 | new Pattern("HiHat: Quarter Notes", new int[] { 80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0 }, "D1", "1/16", "1/16", "Straight"),
25 | new Pattern("HiHat: 8th Notes", new int[] { 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0 }, "D1", "1/16", "1/16", "Straight"),
26 | new Pattern("HiHat: 16th Notes", new int[] { 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80 }, "D1", "1/16", "1/16", "Straight"),
27 | new Pattern("HiHat: Off-Beat 8ths", new int[] { 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80, 0, 80 }, "D1", "1/16", "1/16", "Straight"),
28 | new Pattern("HiHat: On 3rd Beat", new int[] { 0, 0, 80, 0, 0, 0, 80, 0, 0, 0, 80, 0, 0, 0, 80, 0 }, "D1", "1/16", "1/16", "Straight"),
29 | new Pattern("HiHat: Shuffle (Swing 16ths)", new int[] { 80, 0, 40, 0, 80, 0, 40, 0, 80, 0, 40, 0, 80, 0, 40, 0 }, "D1", "1/16", "1/16", "Straight")
30 | };
31 |
32 | /**
33 | * Retrieves a drum pattern by its name.
34 | *
35 | * @param name the name of the drum pattern to retrieve
36 | * @return the drum pattern as an array of integers
37 | * @throws IllegalArgumentException if no pattern is found with the specified name
38 | */
39 | public static int[] getPatternByName(String name) {
40 | for (Pattern pattern : patterns) {
41 | if (pattern.getName().equals(name)) {
42 | return pattern.getPattern();
43 | }
44 | }
45 | // Handle not found case appropriately
46 | throw new IllegalArgumentException("No pattern found with name: " + name);
47 | }
48 |
49 | void init();
50 | }
51 |
52 | class Pattern {
53 | private String name;
54 | private int[] pattern;
55 | private String defaultNote;
56 | private String defaultStepSize;
57 | private String defaultNoteLength;
58 | private String defaultSubdivisions;
59 |
60 | public Pattern(String name, int[] pattern, String defaultNote, String defaultStepSize, String defaultNoteLength, String defaultSubdivisions) {
61 | this.name = name;
62 | this.pattern = pattern;
63 | this.defaultNote = defaultNote;
64 | this.defaultStepSize = defaultStepSize;
65 | this.defaultNoteLength = defaultNoteLength;
66 | this.defaultSubdivisions = defaultSubdivisions;
67 | }
68 |
69 | public String getName() {
70 | return name;
71 | }
72 |
73 | public int[] getPattern() {
74 | return pattern;
75 | }
76 |
77 | public String getDefaultNote() {
78 | return defaultNote;
79 | }
80 |
81 | public String getDefaultStepSize() {
82 | return defaultStepSize;
83 | }
84 |
85 | public String getDefaultNoteLength() {
86 | return defaultNoteLength;
87 | }
88 |
89 | public String getDefaultSubdivisions() {
90 | return defaultSubdivisions;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------