Repository navigation
Releases: Michi71/PicoVintageSynthCollection
Release list
PicoVintageSynthCollection v1.21.1
The cheap-board question from #107 is answered, and the answer is a hardware requirement: the board has to feed the RP2350's core from the chip's own regulator. No firmware change was needed for the boards that work; this release adds the diagnostics that found it and the splash field that tells an A4 chip apart.
The board that stops at 300 MHz (#172)
An unbranded 16 MB "RP2350" board of the kind reported in #107 was bought
and taken apart with a boot-diagnostic image. Its chip is fine, its flash
is fine - the bootrom puts it in quad by itself and it verifies a checksum
at 100 MHz - and every core clock from 312 MHz upward dies inside the
clock switch, while 300 runs. The decisive image ran the core at 300 MHz
with 0.85 V requested from the regulator, and booted to the menu. A
core really at 0.85 V does not do 300 MHz: the regulator register has no
effect on that board's core voltage. The core has been running at the
board's fixed supply all along, and 300 MHz is what an RP2350 manages at
nominal voltage. Nothing in the firmware - flash timing, build option,
stepping - has any bearing on it, and no firmware can get 444 MHz out of
such a board.
The README now says so under Hardware: the engines are budgeted for
444 MHz at 1.60 V through the on-chip regulator, which the Pico 2, the
Waveshare RP2350-Plus and the RP2350B-Plus-W provide, and marketplace
boards that bypass it do not. The symptom is either nothing on the screen
with the release image or "boots at 300 MHz, no sound" with a downclocked
one. The full investigation is in the PicoFaceMD README, The board that
stops at 300 MHz.
Boot diagnostics, for the next board that will not start (#172)
-DPICOFACE_BOOT_DIAG=ON builds an image whose display comes up before
the firmware touches voltage, clock or flash. It shows the stepping, the
bootrom revision and the three QMI registers the bootrom left behind, then
one line per boot stage - vreg, quad, slack, clk, tune,
timing, init done. A board that hangs shows its last completed stage.
-DPICOFACE_EXTRA_DEFINES="..." passes compile definitions to the
instrument targets for one-variable test images (core clock, slack flash
timing, core voltage). Release builds are unchanged: the hook is a null
pointer there.
The splash shows the bootrom revision (#170)
A3 b4 Q 444/148 r4: stepping from CHIP_ID, then the bootrom revision
from the ROM itself. An A4-marked chip reports A3 in CHIP_ID - the
datasheet's 0x8 did not hold on the two such chips seen - and b4 is
the field that tells it. It changes nothing about how the firmware runs;
A4 is a bootrom-only revision and was never the cause of anything here.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC, built for the 16 MB reference board.
For a 4 MB board, build PicoFaceCP yourself with -DPICO_BOARD=pico2 (see
the README, "How much flash an instrument needs"). PicoFaceD5, JV and RD
are not here and never are: they build against Roland ROMs that cannot be
in this repository, so they are local-only builds.
PicoVintageSynthCollection v1.21.0
The reface ports share one MIDI layer, PicoFaceYC finishes its MIDI, and the host tests run in CI. Includes a fix for a PicoFaceDX that played a semitone flat.
PicoFaceDX played 102 cents flat after its first settings write
Found while merging the reface layers (#167): the DX seeded its master tune
with four zero nibbles instead of the data list's centre value 1024, and
applied the tune only when a settings record was restored at boot. A fresh
DX sounded right; a DX that had ever saved its panel - which happens two
seconds after the first knob turn - came up -102.4 cents flat from the next
power-on and stayed there. The shared layer seeds the centre, and a record
written by an earlier release with the zero tune is read as centred, so an
updated DX is in tune without touching its settings.
One reface MIDI layer for CP, DX and YC (#167)
The three ports each carried their own copy of the Yamaha reface dialect -
SYSTEM block, active sensing, channel filter, exclusive framing with byte
count and checksum, the transmit side - and the copies had drifted (the DX
tune above was one of the differences). That is now one core module,
picoface::RefaceMidiBase, with the model's CC map and tone-generator
blocks left to each instrument; the settings autosave the three use is one
template as well. A fix in this layer now reaches all three at once, which
the freeze fix in v1.20.1 would have needed three times had it lived here.
PicoFaceYC: pitch bend, stereo rotary, bulk dump, the model byte (#169)
The YC had carried eight TODOs since its port. They are closed against the
Yamaha reface Data List and the source of Yamaha's own Soundmondo editor,
which agree with each other:
- It is a reface YC on the wire now. Model ID 06H and the 15-byte
identity reply from the data list; the placeholder the port had (model 0,
14 bytes) was one Soundmondo would never have recognised. The tone
generator bulk dump works both ways - a dump request on the bulk header
answers header, 22-byte block and footer, which is exactly what Soundmondo
asks for on connect - and every value an editor sends is clamped to its
documented range before the engine sees it. - Pitch bend, +-2 semitones, on voices and percussion; mod wheel
switches the rotary between SLOW and FAST as on the original; CC7 and
CC11 scale the output - and the percussion now follows the volume, which
it had bypassed entirely. - The rotary is stereo. The left channel is the mono model as it was,
the right hears the horn half a turn and the drum a quarter turn behind,
like a mic pair around the cabinet; the reverb stays mono behind it. With
the rotary off, both channels are what they were, bit for bit.
The MIDI implementation document was rewritten from the data list; what the
firmware chose on its own (the mod wheel threshold, the stereo offsets) is
named there.
Host tests in CI (#166), and the docs caught up (#168)
Every host test that needs neither a sound card nor a ROM set - ten now,
including a round trip through the YC's MIDI layer into its engine - runs
on every push and pull request, and a release is only published when they
are green alongside the seven firmware builds. tools/host_tests/run_all.sh
is the same command locally. The README, the architecture document and
the hardware notes were brought back in line with the boards that exist
and the numbers that are built.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC, built for the 16 MB reference board.
For a 4 MB board, build PicoFaceCP yourself with -DPICO_BOARD=pico2 (see
the README, "How much flash an instrument needs"). PicoFaceD5, JV and RD
are not here and never are: they build against Roland ROMs that cannot be
in this repository, so they are local-only builds.
PicoVintageSynthCollection v1.20.1
DX, YC and CP no longer freeze on a PC that is not reading MIDI.
The freeze, and why it never showed on a Mac
Reported in #161: on a plain Pico 2, PicoFaceDX and PicoFaceYC froze a few
seconds after boot, every release. The board was innocent - it is the other
end of the USB cable.
The reface ports (DX, YC, CP) send MIDI active sensing, one 0xFE every
200 ms, over USB. A PC that has enumerated the device but has no program
holding the MIDI port open never reads the endpoint - Windows and Linux
behave like that - so TinyUSB's 64-byte transmit FIFO is full after sixteen
packets, 3.2 s after boot, and the firmware's transmit queue never empties
again. The display update waited for exactly that queue to drain (so that a
1.5 ms I2C block would not pace a SysEx dump), and the encoders are read
only once the display is done: screen and knobs stood still while the audio
and the MIDI input kept running. macOS reads every USB MIDI endpoint from
the moment a device appears, which is why the freeze was invisible here.
The other instruments send nothing unasked and were never affected.
The core now notices when the host is not taking what is queued - bytes
pending, device mounted, nothing accepted for 50 ms - and stops waiting for
it; the moment the host reads again, everything is back to normal. Dumps to
a host that does read are buffered exactly as before.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC, built for the 16 MB reference board.
For a 4 MB board, build PicoFaceCP yourself with -DPICO_BOARD=pico2 (see
the README, "How much flash an instrument needs"). PicoFaceD5, JV and RD
are not here and never are: they build against Roland ROMs that cannot be
in this repository, so they are local-only builds.
PicoVintageSynthCollection v1.20.0
PicoFaceCP fits a 4 MB flash.
The sample sets, cut where it changes the least
PicoFaceCP was 4.22 MB; a base Raspberry Pi Pico 2 has 4 MB. It is 3.99 MB
now and links on -DPICO_BOARD=pico2 with 190 KB to spare - one set for
every board, no reduced variant.
Nothing was dropped: no region, no velocity layer, and mda-EPiano's own
Rd I data is untouched. The engine plays a sample once and then repeats its
loop cycle for as long as the key is held, so what sits between the bloom
and the loop end is heard exactly once, while the cycle is the sustain.
The five built sets (Rd II, Wr, Clv, CP, Pno) now loop 40-100 ms earlier:
the attack is byte for byte what it was, and the cycle each sample loops
was chosen to stay within 1 dB and 10 % spectral centroid of the cycle it
looped before - where no such window existed, the sample kept its old one.
Measured on the engine, note by note: output identical until the new loop
point, sustain within +-1 dB from there on, loop ripple and release
unchanged.
Three samples that never had a loop - the CP above 97 at high velocity, the
Clavinet's lowest region played softly, the piano's 108 - replayed their
whole attack every 370 ms under a held key. They have an excellent one now.
For anyone rebuilding the sets
tools/cp_sampleprep grew loop_shortest_ms and the loop-cycle
fingerprints (loop_reference.py, reference/*.json) that make such a cut
safe; its README records which recordings the committed headers were built
from, and the configs now point at a loop finder that exists - they used to
name a path that did not, and the pipeline silently fell back to loopless
samples. tools/host_tests/cp has an offline renderer and ab_compare.py
for checking two builds of the sets against each other.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC, built for the 16 MB reference board.
For a 4 MB board, build PicoFaceCP yourself with -DPICO_BOARD=pico2 (see
the README, "How much flash an instrument needs"). PicoFaceD5, JV and RD
are not here and never are: they build against Roland ROMs that cannot be
in this repository, so they are local-only builds.
PicoVintageSynthCollection v1.19.2
The patch page settles down.
One type size, and a name that scrolls
Stepping through a bank used to change the type size with almost every
step: the page picked the largest face the name happened to fit into.
Now the patch number stays put on the left in the value face, the name
takes the rest of the width one size smaller, and where it does not fit
it scrolls - holds still for a moment when a new patch appears so its
start can be read, then runs to the left and comes round again, the way
an LVGL label in LONG_SCROLL_CIRCULAR does. The face never changes.
Small tags mark which encoder owns which half of the page: A for
the patch, B for the value on the row below.
On PicoFaceD5, JV, RD and SM. SM's preset page uses this layout now too.
The display flush pushes only what moved
Under the hood the core no longer pushes the whole screen whenever
anything changes. It keeps a mask of the rows that did, and pushes only
those - for the scrolling name that is two tile rows, about 6 ms of I2C
per frame instead of 24, on the core that also renders the audio, and
nothing at all while the name holds still. Measured on the hardware:
no underruns, PicoFaceD5 at most 60 % CPU with legato across the
keyboard while a long name scrolls.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC. PicoFaceD5, JV and RD are not
here and never are: they build against Roland ROMs that cannot be in
this repository, so they are local-only builds.
PicoVintageSynthCollection v1.19.1
The front panel, made readable — and a decision about the encoders.
The panel
v1.19.0 unified the front panels of all ten instruments on one kit, and
the first report on it (#161) was that it read worse than before:
thinner and smaller type, on a screen that sits off to the side or
behind a keyboard. That was right.
- Bold throughout, and a size up. Values in a 14 px bold face, names
and titles bold as well, lists back in the bold 7x13 they had before.
The value size is the largest bold face that still leaves room for the
knob beside it; the space it needs was measured against what the
instruments actually print, not guessed. - No more footer. CPU load, underruns and dropped packets are for
whoever develops the engine, not for whoever plays it, and they cost
the body nine rows. They have a page of their own now: SYS DIAG in
the SYSTEM section of MD, J6, SM, D5, JV and RD, and the CPU Load
screen under System on CP, DX, YC and OB. - Small things that followed: YC's percussion on/off is the page title
now; the "Sel:Page A/B:edit" hint on CP and OB is gone; the last three
hand-drawn screens (YC About, DX Master Vol, CP Preset) use the kit.
The encoders
They stay as v1.19.0 has them. The board under hardware/ has gone to
production and is the reference hardware from here on; the firmware is
built to match it - one firmware, one wiring. A build from before that
board (prototypes, protoboards) turns the other way since v1.19.0: swap
its two encoder wires. There is deliberately no build option for this.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC. PicoFaceD5, JV and RD are not
here and never are: they build against Roland ROMs that cannot be in
this repository, so they are local-only builds.
PicoVintageSynthCollection v1.19.0
Two things, and they touch every instrument between them.
One front panel for all ten
Every instrument used to draw its own panel — eight of the ten from their own
copy of the same thirty u8g2 calls, which is why the fonts had already started
to drift apart. There is now a shared kit in core/src/ui/kit.cpp: an
instrument states what is on the page — a name, a formatted value, and where
that value sits on its range where it has one — and the kit decides how it
looks.
What you will see on the panel: every value that has a range now shows a
pointer knob beside its number, so the setting reads at a glance without
parsing the digits; page position is dots instead of "3/7"; lists show four
rows instead of three; parameter names have a row of their own, so Emphasis
and Keyboard are no longer cut off. Menus, the preset lists and the About
screen look the same everywhere.
What has not changed: how anything is operated. The section/page
instruments keep their select encoder, the reface ports keep their long-press
menu. What is instrument-specific stayed instrument-specific — the reface DX
algorithm diagram, PicoFaceD5's six-field diagnostics footer, PicoFaceRD's bank
prefix, PicoFaceYC's percussion line.
New with it: tools/host_tests/ui/, which renders any panel on a Mac with no
hardware in about a second. Two layout bugs turned up that way before anyone
had to flash anything.
PicoFaceJ6 measured against Roland's plugin
Roland's JUNO-60 VST3 exposes its whole panel as parameters, so the engine and
the plugin can be given identical settings and played against each other
(tools/j6_vst/). Walking the 56 factory patches that way found causes rather
than symptoms:
- the VCA gate was folded into the contour generator and forced its sustain
to full, which opened the filter too — three and a half octaves out on
gate-mode patches, four of the six worst - cutoff, attack, the two modulation depths, sub and noise, pulse width and
level are measured tables now instead of guessed curves; the cutoff's
bottom sixth was clamped at 20 Hz where the real corner keeps falling to 12 Hz - a contour heading for silence now gets there
- the factory bank is re-transcribed from the owner's manual: 56 patches with
their proper names
Also
- Encoder direction on the board under
hardware/: A and B reach the
RP2350 the other way round there, so clockwise counted down. Fixed in the pin
definition — the names now say which GPIO carries which contact. - Four unreferenced boot splashes and six logo headers removed; the core has
drawn the boot screen itself since the move to the standard runtime model. - A missing bounds check in the PicoFaceOB panel, found by the compiler once
the kit's guards made the range visible.
Binaries
PicoFaceCP, DX, J6, MD, OB, SM and YC. PicoFaceD5, JV and RD are not here
and never are: they build against Roland ROMs that cannot be in this
repository, so they are local-only builds.
PicoVintageSynthCollection v1.18.0
PicoFaceD5's control tick read from the firmware's own timer, plus five VST-measured laws. No hardware or flash changes since v1.17.0; the binaries of the seven other instruments are rebuilt from the same sources.
PicoFaceD5 (built locally from a ROM set, not in these binaries)
- The control tick is 97.66 Hz, not 112: the sound-engine init on EPROM page 3 switches the CPU to 6 MHz (the same routine sets the MIDI baud generator to exactly 31250 at that clock) and runs timer 1 at 10240 µs, whose underflow is the LFO/envelope/portamento tick. The LFO rate table is now the internal ROM's increment table scaled by that tick; Roland's D-50 VST agrees within 1 % from panel 40 to 100. LFO delays and P-ENV times get 14.7 % longer, portamento 12.8 % slower (#156).
- Square and random LFO shapes as the VST plays them on all three routes: the square sits in the upper half of the triangle's swing, the random value is uniform over ±1 (#156).
- The lower tone starts 128 samples (4 ms) after the upper, so two identical tones never sum coherently; Tines, Warm Strings and Slow to Fast Rotor were 6 dB too loud (#156).
- The ring product is formed from DC-free partials, sits 3.3 dB above the plain product of our scaled partials, dies when partial 2 is muted, and shares partial 1's TVA aftertouch range for both partials (#156).
- The low EQ is a first-order shelf; the second-order one was an octave narrower and cost boosted patches 2 to 6 dB (#156).
- Aftertouch and LFO add on top of the cutoff ceiling; the pitch envelope makes its first move 1.4 ticks after the note-on and holds an instant segment for one tick (#156).
- Across the factory bank the per-patch level spread against the VST fell from 2.0 dB (v1.17.0) to 1.7 dB; patches more than 6 dB off from 8 to 2.
Full Changelog: v1.17.0...v1.18.0
PicoVintageSynthCollection v1.17.0
PicoFaceD5 laws from single-partial probes against Roland's D-50 VST. No hardware or flash changes since v1.16.0; the binaries of the seven other instruments are rebuilt from the same sources.
PicoFaceD5 (built locally from a ROM set, not in these binaries)
- TVA aftertouch is quadratic: 0.755 dB × u² with u the range minus 7. A positive range rests fully attenuated (range 14: −37 dB with no pressure) and is lifted linearly by the pressure; a negative one rests at unity and ducks. The old "3 dB" reading was an order of magnitude short. The TVF aftertouch scale rises to match the VST; a PCM partial has no TVA modulation at all, neither LFO nor aftertouch (#155).
- LFO shapes: a synced triangle starts at its top and falls, the sawtooth falls, square and random are ±0.5 with the random value redrawn every half period, and a free-running LFO starts open, which is what the rate-0 tremolos of Ham and Organ and Good and Old Days live on (#155).
- The attack ramps in the log domain like every other segment, at about half the firmware-index duration: T1 40/50/60/70 reach −1 dB at 0.07/0.16/0.38/0.9 s, as the VST does (#155).
- The TVA chip level caps at 142 (velocity sensitivity 100 at full velocity adds 4.2 dB over level 100, not 9), a narrowing square keeps its level down to the 1/16 floor (it used to lose 6.4 dB), and a segment to level 0 ramps to chip zero in its own time and then coasts at that rate to −90 dB (#155).
- Across the factory bank the per-patch level spread against the VST fell from 3.2 dB (v1.16.0) to 2.0 dB; patches more than 6 dB off from 20 to 8.
Full Changelog: v1.16.0...v1.17.0
PicoVintageSynthCollection v1.16.0
PicoFaceD5 corrections from the automated comparison against Roland's D-50 VST. No hardware or flash changes since v1.15.0; the binaries of the seven other instruments are rebuilt from the same sources.
PicoFaceD5 (built locally from a ROM set, not in these binaries)
- Output mode gains as the VST mixes them: mode 1 puts each tone at half amplitude on both outputs, modes 2 to 4 at full on the tone's own output, and a whole patch ignores the mode. The 37 patches in modes 2–4 (Jazz Guitar Duo, Stereo Polysynth, Picked Guitar Duo, Slap Bass n Brass, Pianissimo …) were 6 dB too quiet relative to the rest (#153).
- The TVA, TVF and pulse-width LFO depths read linearly: a tremolo of depth 100 ducks 17.5 dB, downward only. They used to run through the pitch-depth curve and did nothing up to 75; Ham and Organ and Star Peace Chorus sat 25 dB under the VST on their tremolo (#154).
- Envelope segments after the attack rise in the log domain at constant dB/s, like they fall; swelling patches (Alienz in G, DigitalNativeDance, Intruder FX) take the time the VST takes (#154).
- An EQ boost pays half its gain as makeup on the whole signal, as the VST does; cuts do not (#154).
- Probed and found right: TVA bias, TVF keyfollow against coarse, release times, all 100 PCM wave levels and pitches (Loop19 excepted). Across the factory bank the per-patch level spread against the VST fell from 4.2 to 3.2 dB.
Full Changelog: v1.15.0...v1.16.0