Comments (21)
In case you haven't encountered it - Tidal has an interesting way of expressing rhythm: https://github.com/tidalcycles/Tidal/blob/master/doc/tidal.md#sequences.
Not sure if the {}
and []
notations for polyphony are useful when alda already has voices, but a shorthand for repetition and being able to nest these "time warps" is quite convenient.
Regarding the suggested *
syntax, that seems clunky, and in the worst-case more verbose and less readable. Is there an issue with using the regular syntax, and then scaling all note durations based on the given duration of sequence / total of naive note durations in sequence
?
from alda.
I think that this format is actually extremely intuitive and functional, and I can't wait to put it to personal use.
from alda.
Hope that I didn't come across too forthright - more enthused than anything! This is exactly the kind of feature I'd enjoy using too, in the proposed form or with amendments 😄
To clear up what I'm saying about *
as emphasis token, let me use some examples:
{a2 b8 c d e16 f g}4
vs.{e************ b* c* d* e f g}4
(don't make me count){{e f g}* }4
(if we support nesting, docram
s need to support emphasis?){a2 b*}
(is this illegal? what does that mean about recursively calling existing patterns in acram
?)
Hence suggest that the usual notation applies, and actual lengths of notes are calculated by the obvious scaling, ie. {a4 e1}4
would have durations of 1/20th
and 1/5th
of a bar respectively, to give the duration of a quarter note, ie. the same meaning as {a16 e4}4
or {a12 e3}4
from alda.
@crisptrutski I totally agree! I really like what you're proposing -- it's much more elegant than my idea, and probably more intuitive. So basically, we would add up the note values inside the curly braces to get a total note value, and determine each note's lion-share of the total time (the note value to the right of the close curly brace) by dividing it by the total note value. Makes perfect sense to me.
I also like the idea of nesting -- it would make it easier to represent really complex rhythms.
from alda.
Somewhat off-topic, but this paper is a really interesting read involving algorithmic polyrhythms: http://cgm.cs.mcgill.ca/~godfried/publications/banff.pdf
from alda.
Plan on fooling around with this sometime over the coming weekend 🎃
from alda.
🤘🎃🤘
from alda.
OK, I'm cracking this open now!
First idea - use a macro to parse the notes inside the expression, but that fights against the "outside-in" resolution of macros. Next idea is to use binding
to isolate changes to the main *dynamic-vars*
in alda.lisp
(and clear out the events), calculate the new events, scale their offsets and durations, and then reinject those events back into the root scope.
Simpler ideas welcome ^^,
from alda.
Oh, also going to reset the environment's duration to a quarter note in the rebinding also. Let me know if you disagree with this, or if I'm missing any other attributes that need special treatment
from alda.
RE: the grammer, I'm thinking we should only allow events
inside the {}
brackets - correct?
from alda.
RE: the grammer, I'm thinking we should only allow events inside the {} brackets - correct?
Seems legit. We probably don't want to allow voice groups (which are not technically events) or switching instruments inside the brackets. Basically it's like stretching the fabric of space-time around a portion of an instrument part's events 🌌
Oh, also going to reset the environment's duration to a quarter note in the rebinding also. Let me know if you disagree with this, or if I'm missing any other attributes that need special treatment
That sounds OK to me! We can always patch it in the future if it ends up confusing people.
OK, I'm cracking this open now!
First idea - use a macro to parse the notes inside the expression, but that fights against the "outside-in" resolution of macros. Next idea is to use binding to isolate changes to the main dynamic-vars in alda.lisp (and clear out the events), calculate the new events, scale their offsets and durations, and then reinject those events back into the root scope.
Simpler ideas welcome ^^,
I think the approach I would take is to add a new dynamic var like *time-scale-factor*
or something, and use that in the calculation of durations. Then there could be a macro that binds *time-scale-factor*
to a new value and evaluates the body within that context.
from alda.
@daveyarwood OK, that approach might not work, because alter-var-root
refers to.. the root. Don't think we can imperatively mutates dynamic bindings
from alda.
Stretching time is appealing.. the issue is you still need to inspect the time taken before stretching. I guess you could eval with custom bindings, get the duration, then set the stretch-factor and eval again. That way you never nest the bindings and my current hurdle is solved.
Just seems inefficient, going to soldier on a little bit longer 🐻
from alda.
Hmm.. push-thread-bindings
seems to be end of the line unless I code to the Java implementation. That won't be fun to port to CLJS 😨
from alda.
This is the part where I curse you for making alda.lisp
global side effect based 😜
from alda.
Thanks to @crisptrutski's awesome work, we're very close to having C.R.A.M. (we should totally adopt this backronym in the official docs!) implemented. 🎩 🌟
Thinking ahead a bit to the "exact second/millisecond durations" part of this issue, we could implement that as a new alda.lisp
function called exact-duration
or duration-ms
, which acts like a simplified version of duration
that just returns a map that has a :duration-fn
key, e.g. {:duration-fn (constantly 3000)}
. I'm still in favor of adding first-class Alda syntax for this feature, as well, e.g. c60s
(60 seconds), d+500ms
(500 milliseconds)
from alda.
OK, will see about adding that last part tonight. When it comes to "memory" of notes, that is based around beats at the moment, so it might be worth refactoring slightly so that the the duration state can be beat OR duration based, so that tempo changes interact as expected with both kinds of persistence.
Naming wise I'll go with duration-ms
- exact-duration
makes duration
sound a bit too sloppy 😉
from alda.
When I have a chance, I might take a look at trying to simplify the way CRAM is implemented -- it's pretty snappy for me when running small snippets in the REPL, but evaluating multi-poly.alda
takes a while, which makes me wonder if there are performance issues due to the whole "dry run, then rollback" thing.
from alda.
Definitely super slow - added that file as a benchmark intentionally, those nested crams are exponentially expensive. No argument that dry run sucks 😄
Got pretty close to getting it working without in first attempt, but will need either code-walking macros or refactoring of alda.lisp
. Of those I prefer the second 😄
from alda.
(Reopening this until the "exact seconds/millisecond durations" feature is implemented)
from alda.
Working on second/millisecond durations now. I've decided to take a more flexible approach, creating an alternative to note-length
instead of an alternative to duration
.
e.g.:
# alda syntax
2000ms
# parses into
(duration (ms 2000))
The nice thing about this is that it creates the possibility of combining note-lengths (which represent a number of beats and are used in the context of the current tempo to calculate the length of the note in ms) with exact second/millisecond durations:
# alda syntax
4~2000ms
# parses into
(duration (note-length 4) (ms 2000))
The above duration == however long a quarter note is at the current tempo, plus 2000 ms.
from alda.
Related Issues (20)
- player processes get stuck HOT 14
- How to make Pedal On and Off in Alda HOT 4
- Can't Create Chord with Cram Expression HOT 6
- Alda REPL: "Play right away" offset calculation doesn't work with voices HOT 1
- Alda REPL server sometimes "claims" more than 1 player on startup
- Exiting Alda REPL in "server only" mode kills all player processes
- Alda REPL "skips" rests at the end of a line
- open /tmp/alda-doctor1917232005/1666820313.mid: no such file or directory HOT 6
- Are there any PORTABLE version of alda that can run without java? HOT 1
- Time to play is too long HOT 15
- can I see debug messages while the player is running? HOT 4
- `pitch` behavior changed from Alda 1 to Alda 2 HOT 4
- Lisp function `part` got deleted in Alda 2 HOT 1
- No way to download Alda 2 HOT 4
- `exec java` resolving to the wrong path HOT 4
- cannot run alda HOT 3
- No Sound HOT 5
- client/parser/scanner.go: invalid rune quoting HOT 9
- Can i generate an mp3 with my code? HOT 3
- [BUG] MIDI failure in JVM on fresh install cause alda and alda-player to both fail HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from alda.