Skip to content

Commit

Permalink
Merge pull request #8 from kanduvisla/develop
Browse files Browse the repository at this point in the history
Release 0.4
  • Loading branch information
kanduvisla authored Nov 1, 2024
2 parents 902d176 + 5df988a commit 3672440
Show file tree
Hide file tree
Showing 5 changed files with 475 additions and 146 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- main

env:
VERSION: v0.3
VERSION: v0.4

jobs:
package-and-release:
Expand Down
87 changes: 52 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,67 +14,84 @@ The plugin is accessible under `Tools > Live`, and basically does the following:

- The **only** pattern that is every playing is pattern **0**.
- The tool copy/pastes the source pattern the pattern 0 every time a loop has ended or when a fill / transition is triggered.
- It is during this copy/paste event that `Lxxx`-effects are processed and your pattern is mutated.
- It is during this copy/paste event that [some](##-features) `Zxxx`-effects are processed and your pattern is mutated.

This basically means that you need to use Renoise in a slightly different way than you're used to:

- Don't put stuff in pattern 0: it **will** get overwritten by this tool.
- It's pretty useless to play a pattern outside of the live tool, because the `Lxxx`-conditions are only triggered when you start your project from the Live-tool (e.g. all notes will be triggered at once).
- It's pretty useless to play a pattern outside of the live tool, because the `Zxxx`-conditions are only triggered when you start your project from the Live-tool (e.g. all notes will be triggered at once).
- It **is** possible to live edit: just start the live tool, navigate to the pattern you want to edit and start editing. Just be aware that at all times it's pattern 0 that is playing, and your work will only be copy/pasted/processed to pattern 0 the moment the pattern has finished a cycle (e.g. played it's last note and goes back to note 1).
- For a complete list, see [known issues and limitations](##-known-issues-and-limitations)

## Features

This tool adds the following effects to the pattern editor:

- The following effects are applicable to both **columns** and **tracks**:
- Note triggers
- `LT01` : Only play the first run of this pattern.
- `LT00` : Don't play the first run of this pattern.
- `LTn0` : Only play the nth run of this pattern.
- `LTyx` : Play every xth pattern after y runs. Some examples:
- `LT21` : Play the note on run 1, but not run 2 (`2:1`)
- `LT33` : Play the note on run 3, but not on 1 and 2 (`3:3`)
- `LIyx` : Inverted trigger (Don't play every xth pattern after y runs). Some examples:
- `LI41` : Play the note on run 2, 3 and 4, but not on 1 (`4:1`)
- `LI33` : Play the note on run 1 and 2, but not 3 (`3:3`)
- Fills
- `LF00` : Only play when not having a fill/transition to another pattern
- `LF01` : Only play when having a fill/transition to another pattern
- Muting
- `LM00` : Start track muted
- `LMxx` : Unmute after `xx` runs (in dec)
- Note t**r**iggers (`ZR` and `ZI`)
- `ZR01` : Only play the first run of this pattern.
- `ZR00` : Don't play the first run of this pattern.
- `ZRn0` : Only play the nth run of this pattern.
- `ZRyx` : Play every xth pattern after y runs. Some examples:
- `ZR21` : Play the note on run 1, but not run 2 (`2:1`)
- `ZR33` : Play the note on run 3, but not on 1 and 2 (`3:3`)
- `ZIyx` : **I**nverted trigger (Don't play every xth pattern after y runs). Some examples:
- `ZI41` : Play the note on run 2, 3 and 4, but not on 1 (`4:1`)
- `ZI33` : Play the note on run 1 and 2, but not 3 (`3:3`)
- **F**ills (`ZF`)
- `ZF00` : Only play when not having a fill/transition to another pattern
- `ZF01` : Only play when having a fill/transition to another pattern
- **M**uting (`ZM`)
- `ZM00` : Start track muted
- `ZMxx` : Unmute after `xx` runs (in dec)
- The following effects are applicable to **only tracks**:
- Automatically set next pattern
- `LNxx` : Set pattern `xx` (in dec) to be the next one in the queue.
- Set pattern play count
- `LPxx` : Set pattern play count to `xx` (transitions will be triggered in the last count). When a next pattern is queued, the current pattern plays a full `xx` runs. For example: a 16-bar pattern with `LP04` will always play in sets of 4, but you can already queue it on the first run. Fills will be triggered in the last run.
- Cutoff pattern (useful to generate polyrhythms)
- `LC00` : Cut off (and repeat) the pattern from this point. This is up to but not included, so a cut on line 4 would repeat lines 1,2 and 3; effectively creating a [polyrhythm](https://en.wikipedia.org/wiki/Polyrhythm).
- Triggs (`LT`) and inverted triggs (`LI`) are supported when a track uses `LC`
- Fills (`LF`) and muting (`LM`) are not supported when a track uses `LC`
- Automatically set **n**ext pattern (`ZN`)
- `ZNxx` : Set pattern `xx` (in dec) to be the next one in the queue.
- Set pattern **p**lay count (`ZP`)
- `ZPxx` : Set pattern play count to `xx` (transitions will be triggered in the last count). When a next pattern is queued, the current pattern plays a full `xx` runs. For example: a 16-bar pattern with `ZP04` will always play in sets of 4, but you can already queue it on the first run. Fills will be triggered in the last run.
- **C**utoff pattern (useful to generate polymeter / polyrhythms) (`ZC`)
- `ZC00` : Cut off (and repeat) the pattern from this point. This is up to but not included, so a cut on line 4 would repeat lines 1,2 and 3; effectively creating a [polyrhythm](https://en.wikipedia.org/wiki/Polyrhythm).
- Triggs (`ZR`) and inverted triggs (`ZI`) are supported when a track uses `ZC`
- Fills (`ZF`) and muting (`ZM`) are not supported when a track uses `ZC`

## Keyboard shortcuts

- `arrow left` : queue previous pattern
- `arrow right` : queue next pattern
- `f` : trigger fill
- `esc` : close dialog
- `1` to `8` : mute / unmute track 1 to 8
- `q` to `i` _(upper keys on a qwerty keyboard)_ : mute / unmute track 9 to 16

## Ideas

This is a rough lists of ideas that I want to add to this plugin in the future:

- Get text from song and translate to instructions per pattern
- Add mute / unmute buttons to UI
- Queue mute / unmute
- When queueing mute, do play the first note before muting
- When queueing mute, do play the first note before muting
- Add trig condition that only plays on the first pattern after a fill
- suggestion: `LF02`
- suggestion: `ZF02`
- Add trig condition that doesn't plays on the first pattern after a fill
- suggestion: `LF03`
- suggestion: `ZF03`
- Alternative fill
- suggestion: `ZF04`
- "Break" mute / fill (mute (a group?), do a fill and then unmute again)
- Force unmute
- Stutter / randomize track
- Muting Groups - where you can mute/unmute multiple tracks at once
- Track playback speed (1/2, 1/3, 1/4, 1/8, 1/16, 1/32, 1/64)
- Also stretch delay column
- suggestion: `ZSxx`
- One tap on stop should not reset pattern, stop while stop should
- External midi syncing / queueing
- More optimizations (any help is welcome)

## Known issues & limitations

- Things break when loading a new song while the Live dialog is open. Close the dialog before opening a new song.
- Line effects are only measured on effect column 1
- Fills don't work in tracks that are cut with the `LC` command
- Muting in tracks don't work in tracks that are cut with the `LC` command
- When live-editing a track with a `LC` command, funky things will happen due to the virtual counting.
- Possibly a Renoise bug, but when you delete an effect from a track, the `L` in the FX column changes (to a `K` for example).
- Fills don't work in tracks that are cut with the `ZC` command
- Muting in tracks don't work in tracks that are cut with the `ZC` command
- When live-editing a track with a `ZC` command, funky things will happen due to the virtual counting.
- Transitioning between patterns of different lengths not yet very stable. Using `ZB00` on the end of your pattern helps when the next pattern is longer, but when transitioning from a longer to a shorter pattern it's not really stable yet.
- The Mute buttons of the UI only apply to tracks. So when applying on columns, it makes sense to make use of the timed muters
24 changes: 12 additions & 12 deletions includes/cutoff_points.lua
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
-- Process cutoff points ("LC" effect)
-- Process cutoff points ("ZC" effect)
-- If no cutoff points were found / processed, this funtion returns false
process_cutoff_points = function(t, dstPattern, srcPattern, song, trackLengths, patternPlayCount)
local dstTrack = dstPattern:track(t)
local numberOfLines = dstPattern.number_of_lines
for l=1, numberOfLines do
-- Check for "LC" filter
if dstTrack:line(l):effect_column(1).number_string == "LC" then
-- Check for "ZC" filter
if dstTrack:line(l):effect_column(1).number_string == "ZC" then
-- A cutoff point indicates a place in the track where a selection needs to be copy/pasted.
-- This means we "fill" the pattern with everything that is above the LC, and keep track of how many
-- This means we "fill" the pattern with everything that is above the ZC, and keep track of how many
-- times it has already copied to keep the remainder in mind.

-- How many times does this pattern "fit" in this track:
local duplicationCount = math.ceil(numberOfLines / trackLengths[t]) + 1

-- Copy from first line up until the line with the "LC" effectL
-- Copy from first line up until the line with the "ZC" effect:
for fl=1, l - 1 do
-- Offset from the previous iteration:
local offset = (patternPlayCount * numberOfLines) % trackLengths[t]
Expand All @@ -30,16 +30,16 @@ process_cutoff_points = function(t, dstPattern, srcPattern, song, trackLengths,
local lineEffect = srcLine:effect_column(1)

-- Fill:
if lineEffect.number_string == "LF" then
if lineEffect.number_string == "ZF" then
-- TODO, how to do fills with polyrhythm?
elseif lineEffect.number_string == "LT" then
elseif lineEffect.number_string == "ZR" then
-- Trigger:
if is_trig_active(lineEffect.amount_string, virtualTrackPlayCount) then
dstTrack:line(dstLine):copy_from(srcLine)
else
dstTrack:line(dstLine):clear()
end
elseif lineEffect.number_string == "LI" then
elseif lineEffect.number_string == "ZI" then
-- Inverse Trigger:
if not is_trig_active(lineEffect.amount_string, virtualTrackPlayCount) then
dstTrack:line(dstLine):copy_from(srcLine)
Expand All @@ -59,14 +59,14 @@ process_cutoff_points = function(t, dstPattern, srcPattern, song, trackLengths,
local effect_number = column.effect_number_string
local effect_amount = column.effect_amount_string
-- Fill:
if effect_number == "LF" then
if effect_number == "ZF" then
-- TODO, how to do fills with polyrhythm?
elseif effect_number == "LT" then
elseif effect_number == "ZR" then
if not is_trig_active(effect_amount, virtualTrackPlayCount) then
column:clear()
end
-- Inversed Trigger:
elseif effect_number == "LI" then
elseif effect_number == "ZI" then
if is_trig_active(effect_amount, virtualTrackPlayCount) then
column:clear()
end
Expand All @@ -78,7 +78,7 @@ process_cutoff_points = function(t, dstPattern, srcPattern, song, trackLengths,
end -- end for#fl

return true
end -- end if#"LC"
end -- end if#"ZC"
end -- end for#numberOfLines

return false
Expand Down
Loading

0 comments on commit 3672440

Please sign in to comment.