[0.1.12]
Added
TuningFork.Stage.layers/3takesfrom_start: true: the new layers begin at their own start instead of at the playhead.TuningFork.Stage.drop_layers/2stops named layers while the rest play on (TuningFork.Stage.Bed.drop/2).TuningFork.Mixer.fit/5: PCM moved to another rate and channel count.TuningFork.Xwma: xWMA audio (WMA v2 packets with their seek table, as XACT wave banks hold it) wrapped as an.xwmafile and decoded to PCM by the first availableTuningFork.Xwma.Decoder:TuningFork.Wmawhen a package provides it, else the machine'sffmpeg(TuningFork.Xwma.Ffmpeg);:xwma_decoderssets the order.TuningFork.Musreads DMX MUS, Doom's music format, into the sameTuningFork.Midivalue a MIDI file reads into, soTuningFork.Gm.score/2plays it.TuningFork.Envelope.gated/2and the envelope's:gate: the envelope played as a key held for so many seconds and then let go, releasing from whatever level it had reached.TuningFork.Stage.play/3takes:key,:gain,:panand:fade: a voice played under a key replaces the one sounding there and plays to the end of its envelope.TuningFork.Stage.hold/4takes:gain,:panand:fade.TuningFork.Stage.place/3moves what sounds under a key to a new:gainand:panwhile it plays, spread across the next chunk; a key's placement carries over to the next voice sounded under it.TuningFork.Stage.play_pcm/3takes the same options: mono PCM played under a key is placed and moved like a voice, andTuningFork.Stage.release/3fades it. Held in aTuningFork.Stage.Clip.TuningFork.Mixer.place/4: a mono buffer placed in the field while its gain and pan move in a straight line from one{gain, pan}to another.
Changed
TuningFork.Midi.to_score/2holds each note's key for the note's length and lets it go at the end (Envelope.gated/2) rather than stretching the synth's decay over the note: a long note decays in the synth's own time and holds its sustain, and a struck voice dies away rather than ringing to the note's end. The default voice sounds at full level for as long as a note is held.TuningFork.Midi.to_score/2plays channel volume (controller 7) and expression (11) as General MIDI does — volume 100 and expression 127 until the file sets them — as a:gaincurve when they move while a note sounds, and pan (10) as the voice's:pan. A file that never sets its volume plays at 100/127 of its former level.:level_pointscaps the curve's breakpoints, default 32.
Fixed
- A voice or PCM let go under a key keeps its key while it fades, so it fades at its
placement and
place/3still moves it.
Breaking changes
- None since 0.1.11. An app moving from 0.1.7 or earlier registers its SFZ instruments with
TuningFork.Sfz.register/2(see 0.1.8).
[0.1.11]
- Released alongside the family; no changes to this package.
[0.1.10]
- Released alongside the family; no changes to this package.
[0.1.9]
- Released alongside the family; no changes to this package.
[0.1.8]
TuningFork.Sfzcarries no instruments of its own. The application registers the ones it plays withTuningFork.Sfz.register/2(orregister/1for many), each with its source, licence, credit and what it is, or underconfig :tuning_fork, :sfzas before;instruments/0lists what is registered. The FreePats, E-Pianos, Splendid Grand and Karoryfer entries the library used to list are gone from it.TuningFork.Sample.Fetch.settle/0waits until every fetch and background task under way has finished;TuningFork.Sample.Font.clear/0waits for them before forgetting the loaded fonts.
[0.1.7]
- Released alongside the family; no changes to this package.
[0.1.6]
TuningFork.Sfzreads an SFZ instrument into a pitchedTuningFork.Sample.Bank: one velocity layer (:velocity, default 100), every round robin of a note, loops, and an optional:keysrange.load/2takes a name frominstruments/0, agithub:user/repo/branch/pathsource, a URL or a local path; recordings are fetched as notes ask for them, or all at once withprefetch: true. The kit plays a known name as a sound —s("fingerbass")— and loads it the first time a pattern plays it.TuningFork.Midi.mini/2gives one channel of a MIDI file as Strudel mini-notation,{bars, mini}, a[…]of steps per bar. Options::channel,:beats_per_bar,:steps_per_beat,:from,:bars,:voice(:all,:lowest,:highest),:on(:steps,:beats) and:transpose.TuningFork.Stagerenders a pattern in a process of its own,TuningFork.Pattern.Ahead, a few chunks ahead of the stream.update_pattern/3,pattern_gain/2,pattern_cps/2andhush/1sound within those chunks;cycle/1reports how far the rendering has reached.Pattern.Player.new/3andStage.start_pattern/3take:parallelto render the sounding voices on every core; defaultfalse.Cache.fetch/4takes:dirandCache.path/3a directory, defaultCache.dir/0;fetch/4removes an earlier fingerprint of the same key.Sample.Bank.put/3takes a file as{path, opts}with options of its own (:loop,:gain,:root), and a pitched map's note as a MIDI number, fractional when the recording lies between two notes.Sample.from_pcm/2takes:gain.Mixer.silent?/1says whether every sample is zero;Mixer.mix/1passes over silent buffers and pads the result to the longest one.Sample.Fetch.get/1leaves characters that are already percent-encoded as they are.TuningFork.Strudeltranslates string literals of any length in full.TuningFork.Sink.Tcp's:warm_up_msdefaults to0;:prime_framessets how many frames go at once before a warm-up, default1024. Its log lines are prefixedtuning_fork:like the rest of the library's.
0.1.5
TuningFork.Sink.Process— each chunk of raw signed 16-bit PCM as a{:pcm, binary}message to a process, paced to real time with:lead_msin flight.TuningFork.Sink.Tcp— raw signed 16-bit PCM over a TCP connection, paced to real time with:lead_msin flight, connecting on the first write and again every:retry_mswhen the far end is not there;:warm_up_msgives a player that buffers while it opens its device that long before real time starts.
0.1.4
Stage.pattern_gain/2andPattern.Player.gain/2scale a pattern's whole output, sounding notes included;0.0is silence.
0.1.3
- A
TuningFork.Partsynth may be a function of the note — an instrument — andTuningFork.Kit.instrument/4makes one from any sound name, so a part plays a soundfont or a bank recording at each note. Part.repeat/3takes a string ofxand.as well as a count: a pass plays onxand keeps its place silently on..- A bank the kit does not have starts
TuningFork.Strudel.defaults/1loading, and a voice asked for withwait: truewaits for it;Strudel.defaults(wait: true)andSample.Set.load_all/2are the waited-for forms. sdis a snare name; mini-notation reads-.3.Envelope.spanning/2drops the envelope's hold, so a note asked to lastsecondsdoes — a voice with a hold, such as a soundfont's, used to ring on past it.
0.1.1
bank/2keeps the bank name on each event; the kit plays the recording registered asbank_soundwhen the bank has it, and its own drum until then. Before, a name inTuningFork.Kit.banks/0never reached the recordings.struct/2keeps every note sounding at a structural step, so a voiced chord understructsounds whole.use_synthtakes a sound name —use_synth "gm_epiano1"— played at each note through the kit.TuningFork.Kit.known?/1says which names qualify.- A sample file whose name has a space in it is fetched.
- A step whose edge fell a rounding error inside a query span could be reported twice;
Pattern.query/2leaves such slivers out.
0.1.0
First release.