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 { ... } parameters { standard extensions { tXX - set tween time (in ticks) for previous parameter ,XX - extra param bytes } InstrumentCore (stock instrument behavior) { legato accepts tweens! must be first parameter entry vXX - volume; 00 .. FF -> 0.0 .. 1.0 (accepts tweens) pXX - panning; signed byte? 00 as center (accepts tweens) gXX/GXX - glissando (pitch bend); g=down, G=up; relative semitones (accepts tweens) rXX - vibrato; first byte is ticks per full cycle, second byte is how much to bend (0x10 == 1.0, defaults to 0.25) ^ if first byte is 00, keeps speed if bend specified, else stops vibrato } global port (G) { tXX - tempo (how to implement >255? fine tempo?) } } TODO { settings dialog { about-license info } > add common oscillators to a nodelib header revert-to-saved menu action automation node { listens for one specific param supports tweening value bounds, scaling exponent passthrough command port with option to consume marked param how to UI? I guess some sort of text box/spinner to enter bounds dial for exponent focusable control to set param } editing song info should probably be an UndoStack action editing song *tempo* ABSOLUTELY should maybe retool rendering to feed f32 (or even f64) to ffmpeg figure out what to actually do with directory config buffer helper akin to what quicklevel does { keeps a buffer length, running averages, etc. can lerp across tick for speed useful for level reading, waveform output, compression/sidechaining etc. } solo gadget { interprets incoming commands as monophonic with portamento probably not super useful for tracked things but good for playing live } color scheme load/save maybe a similar abstraction for processing notes to what commandreader does maybe interpolate between resampler LUT levels bugs to fix { pattern switching is slow when changing (especially increasing) number of rows; set fixed page size to avoid reallocation? } misc features needed before proper release { ABOUT BOX WITH INCLIB LICENSE NOTICES expand/compact pattern 2x/3x, keeping fold interval at *least* js plugin support, with lua+lv2 highly preferable different context menu for multiple selected nodes / pack/unpack selection to/from subgraph (partial; can copy/paste a selection) proper playback controls and indicators play from current pattern pattern editor cells can have (dynamic) tool tips; set this up with port names, etc. make the save routine displace the old file and write a new one } 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) - quick drum sequencer (BeatPad) - quick single-sample "wavetable" (Capaxitor) full-fat tracker sampler at some point } } Xynamo (hybrid? synth) { 3? 5? oscillators; several different waveforms available, independent filtering, wavefolding and (hard) wrapping... individually controllable?? rail system! } - 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