200 lines
9.1 KiB
Plaintext
200 lines
9.1 KiB
Plaintext
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
|
|
https://github.com/ThePhD/sol2
|
|
https://github.com/cameron314/concurrentqueue
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
unique port for globals (-2 internally, styled as (G), and placed by, get this, pressing g) {
|
|
what to do with the notes?
|
|
tXX - tempo (second tXX as high byte, .XX for fine tempo (0..100))
|
|
> anything else?
|
|
}
|
|
}
|
|
}
|
|
|
|
TODO {
|
|
immediate frontburner {
|
|
patchboard copy+paste! cbor array of node objects
|
|
position: copy relative to centroid, paste relative to center of viewport
|
|
also record connections between those particular nodes!
|
|
- provide conversions to/from qcborvalue in node.cpp?
|
|
> while we're here, add file import/export of any given node (.xyn)
|
|
|
|
probably exclude i/o ports from copy+paste lest things futz up on the parent
|
|
}
|
|
|
|
-? return the latency/buffer size to 100ms once multithreading is streamlined
|
|
# fix how qt5.12 broke header text (removed elide for now)
|
|
|
|
pseudoport (L) for legato (note-on for already-playing note)
|
|
make knob notches more even (currently "previous value" is twice as big as any other step at px>1)
|
|
add standardized step values for knobs (int enum?)
|
|
|
|
bugs to fix {
|
|
graph connections sometimes spawn in duplicated :|
|
|
|
|
on starting playback, sometimes a "thunk" sneaks into the waveform?
|
|
|
|
-? buffer underruns are being caused by some sync wonkiness between multiple workers
|
|
}
|
|
|
|
misc features needed before proper release {
|
|
song metadata (title, artist, comment, default bpm)
|
|
|
|
at *least* js plugin support, with lua+lv2 highly preferable
|
|
SAMPLES and SAMPLING
|
|
|
|
- gadget widgets (w/container) - at least a knob with nice range and such
|
|
|
|
different context menu for multiple selected nodes
|
|
pack/unpack selection to/from subgraph
|
|
import/export subgraph as file (*.xyg)
|
|
|
|
proper playback controls and indicators
|
|
play from current pattern
|
|
- instrument previewing
|
|
|
|
pattern editor cells can have (dynamic) tool tips; set this up with port names, etc.
|
|
? de-hardcode the "» " (probably just make it a static const variable somewhere?)
|
|
make everything relevant check if editing is locked
|
|
|
|
make the save routine displace the old file and write a new one
|
|
|
|
open file from command line argument
|
|
^ multi-document, single-instance (QLocalServer etc.)
|
|
}
|
|
|
|
gadgets and bundled things {
|
|
(the simple things:)
|
|
- gain and panning gadget
|
|
- note transpose
|
|
volume meter
|
|
|
|
"wrap clipper" (gain up, then wrap around +-1.0, then gain down)
|
|
|
|
Polyplexer (splits a single command input into several monophonic outputs and keeps track of individual notes between them)
|
|
|
|
probably three sorts of sampler (quick drum sequencer, quick single-sample "wavetable", then the full-on tracker sampler later on)
|
|
}
|
|
}
|
|
|
|
- dumb per-cycle atomic memory allocator from fixed pool for port buffer allocations
|
|
? can also set up a tlsf pool per worker; prefix allocations with single byte identifier indicating which one they came from,
|
|
? and defer freeing operations via message queues
|
|
|
|
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?)
|
|
}
|
|
|
|
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 (graph-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)
|
|
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)
|
|
}
|
|
|
|
on-the-wire command format {
|
|
uint16_t noteId // for sending commands to the same note
|
|
int16_t note // note number >= 0, -1 for none, -2 note off, -3 hard cut
|
|
uint8_t numParams x {
|
|
uint8_t cmd
|
|
uint8_t 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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
to revert to stable repo copy of qt:
|
|
yay -S qt5-base qt5-declarative qt5-doc qt5-graphicaleffects qt5-location qt5-multimedia qt5-quickcontrols qt5-quickcontrols2 qt5-script qt5-sensors qt5-speech qt5-svg qt5-tools qt5-webchannel qt5-webengine qt5-websockets qt5-x11extras qt5-xmlpatterns
|