xybrid/notes

179 lines
7.5 KiB
Plaintext
Raw Normal View History

2018-12-01 10:41:14 -05:00
IMPORTANT LINKS {
https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
lowpass filter https://www.embeddedrelated.com/showarticle/779.php
2018-11-20 14:03:21 -05:00
}
project data {
samples are held in memory as {
QString name, QUuid id (used as dictionary key) (?)
sample rate, channel count (1 or 2), length
probably QSharedPointer to raw float array (size=length*channels, non-interleaved)
}
pattern {
name, id
length in rows (duh)
time signature: beats/measure, rows/beat, ticks/row (can default to project global? except that doesn't make complete sense)
tempo change on enter (float, defaults to 0; only applied if >0)
when creating new pattern {
time signature set to project defaults (either static or fallback)
rows = 4 measures
}
2018-11-20 14:03:21 -05:00
per-pattern channels; note continuity is defined by name
^ by default, send note-off on entering a pattern without a channel of that name
also send note-off on old note when triggering a new one regardless of what instrument it is,
*AFTER* sending the new note-on (to not break or make things harder for legato instruments)
2018-11-20 14:03:21 -05:00
command format
01 C-5 v7F ... ... ...
instrument (port) number first; note-sharp-octave notation same as most trackers, but arbitrary number of a single type of parameter
[plugins receive commands more or less exactly as written; meaning is by convention more than anything, but there is a "standard" way of handling notes, handled by a library on the lua side]
- leave pitch bends to automation? or build them as per-tick messages from host? also, stepped by tick or smoothed per sample?
x note-on events send the actual note as a float value
- nope, separate event for cents (bcd? that would futz with interpolation though... signed byte, -100..100)
treat port FF as global control?? {
what to do with the notes?
tXX - tempo (second tXX as high byte, .XX for fine tempo (0..100))
> anything else?
}
2018-11-20 14:03:21 -05:00
}
}
TODO {
immediate frontburner {
- allow swapping channels around
2018-12-01 10:41:14 -05:00
- double click to rename channel - popup for now since QHeaderView doesn't actually implement editing via delegate...
- right click channel header:
- rename
- add
- delete
toggle box for expand-to-name
2018-12-01 10:41:14 -05:00
- create new Project and hook that up to the main window instead of just making an empty pattern
make and hook up UI for displaying all existing patterns by index...
...and for displaying the sequence
implement drag and drop for pattern swapping/rearrangement (std::rotate)
add miscellaneous editables (artist, song title, project bpm; pattern name, length etc.)
2018-12-01 10:41:14 -05:00
make splitter collapse update pattern editor
- make pattern editor detect ctrl and alt modifiers
make everything relevant check if editing is locked
- figure out what library to use for messagepack (official msgpack-c)
implement saving (probably a FileIO helper class)
2018-12-01 10:41:14 -05:00
- hook up new/open/save menu items
}
? de-hardcode the "» " (probably just make it a static const variable somewhere?)
pattern background colors (and time signature, duh)
pattern editor cells can have (dynamic) tool tips; set this up with port names, etc.
project type {
how to bind to mainwindow?
}
at some point {
undo
multiselect editing (at least delete)
de-hardcode pattern editor colors
}
}
use signals/slots to signal project/pattern updates etc.
saving and loading {
msgpack object
probably have a field of raw data for (some) node saves, and keep it resident in case of plugin crashes
}
2018-11-20 14:03:21 -05:00
resampler object {
one used internally for each note
reference to sample
wrap mode (flat, loop, pingpong)
double position (number of samples with fractional part)
}
gain slider/knob gadget: dBFS [10^(x / 20)]
scale from -60 to +6 in increments of .1, with linear fade to zero below -60
sine panning http://folk.ntnu.no/oyvinbra/delete/Lesson1Panning.html
though for vXX, it's perfectly sufficient to use mult^4
JS example of sine panning, -1.0 to +1.0 {
const m = 1.0/Math.cos(Math.PI*.25)
function f(x) {
var s = (x+1) * Math.PI * .25
return (Math.cos(s)*m) + " " + (Math.sin(s)*m)
}
}
plugin registry {
queuing function for static construction
PluginInfo base class, virtual function for creating a node of said plugin
(separate function for loading from save file?)
}
2018-11-20 14:03:21 -05:00
lv2 support: lilv (duh) for actual plugin loading, suil for UI embedding
eventually hook luajit up with TLSF allocator to aid in real time (maybe look at nedmalloc too)
(requires a patch to lib_aux.c, so static link/straight include?)
https://github.com/OpenMusicKontrollers/Tjost/blob/master/LuaJIT-2.0.3-rt.patch
to static link https://stackoverflow.com/a/30235934
graph+node+port system {
dependencies are a straight ordering, worked backwards from the mix output on port hookup change (node local)
this way, we don't bother processing anything that doesn't actually contribute to output in any way
before playback starts, playback thread assembles an expanded queue (graph has a function that recursively expands queue given a ref to a pre-reserved vector)
2018-12-01 10:41:14 -05:00
note: also preassemble a map of all unique channel names for note number purposes
can use the same logic to count active nodes (make sure to include the graph i/o ports unless implementing those another way? actually yeah, explicit pull operation)
... how will the worker threads tell when they've outpaced the queue, and how will they wait properly?
something something ready flags (all input nodes and containing graph; main graph and command ports always have the bit set)
graphs are also nodes
can use locks on processing node-ports since they'll basically never be contended; this allows for editing during playback
^ or just double-buffer the connections
UI thread takes full responsibility for both replacement and eventual collection; atomic bool marking is enough threadsafety to deflect the collection timer
have to signal playback thread that queues have been invalidated
...or just use locks and a flag since it's probably not worth the added complexity of implementing lockfree to avoid hangups when *fiddling with connections*
though we do want a queue system for plugin parameter changes! don't want xruns from fiddling with instruments or mixing
(most built-in gadgets can avoid this by nature of aligned power-of-two types (<=8bytes) inherently atomic on modern CPUs)
}
2018-12-01 10:41:14 -05:00
on-the-wire command format {
ushort noteId // for sending commands to the same note
short note // note number >= 0, -1 for none, -2 note off, -3 hard cut
unsigned char numParams * {
unsigned char cmd
unsigned char amount
}
}
keybinds {
pattern editor {
note column {
( a-z, []\ ;' ,./ ) - "flat piano" in three octaves a la openMPT (maybe minus /)
shift - hold to transpose up one or two octaves while playing
1234567890 - assign octave
note off, hard cut?
}
param column {
symbol {
anything printable - set symbol and move to value
}
value {
minus - negate current value
}
}
}
}