Releases: JonasGrunau/open_audio_analyzer
Releases · JonasGrunau/open_audio_analyzer
Release list
Open Audio Analyzer v0.11.0
📐 Measurement
- Audio missed while the capture source was stopped is now counted as lost
audio, so the frame count includes it and the warning appears. It previously
counted nothing at all: integrated loudness and LRA average every block since
the reset, so a device that stopped for a minute produced a reading of the
programme minus that minute and presented it exactly like a clean one. A
stall's share of the count is derived from the analysis clock rather than from
the ring, so it is accurate to about a quarter of a second rather than to the
frame — enough to prove audio was lost, which is what the figure is for.
Re-measure any session where the warning appeared. - The System Output tap no longer measures an output device that has changed its
own sample rate. A macOS output device can move rate without ceasing to be the
default output — AirPods drop from 48 kHz to 24 kHz the moment anything opens
their microphone — and the tap went on delivering while the K-weighting
filters, the true-peak oversampler, the spectrum's frequency axis and the
elapsed clock all stayed built for the rate the engine opened at. Every
reading was then wrong by the ratio between the two rates: at half the rate
the spectrum sat an octave low and the elapsed clock ran at half real time,
with the meters moving convincingly throughout. The source is now reported as
stopped and reopened at the device's new rate. Re-measure anything metered
through System Output on a Bluetooth output device.
✨ Added
- A File menu, and presets that are documents.
Open…picks a preset
through the platform's own dialog, starting in the presets folder and reaching
anywhere else you point it — a preset somebody sent you now opens where it was
downloaded to, instead of having to be moved into the configuration directory
first.Savewrites back to the file it came from without asking,Save as…
places a copy anywhere and names the preset after the file, and the open
preset's name sits at the left of the status bar with a dot beside it when it
differs from what is on disk. On macOS the menu is in the system menu bar,
after the application menu; on Windows and Linux it is the FILE button in the
status bar. Opening a preset over unsaved changes asks whether to save first. - A privacy policy, at
open-audio-analyzer.com/privacy.
It states what the microphone, the camera, the local network and the disk are
used for, that nothing is collected or transmitted, and — the part worth
reading — that the remote display link has neither encryption nor
authentication, so publishing on a network you do not trust means anybody on
it can read your meters. App Store Connect requires the URL; the page is
written for a person rather than for that field.
⚡ Changed
- The website serves its three typefaces itself instead of loading them from
Google Fonts. Reading a page no longer makes a request to Google, which
previously saw the IP address of everybody who opened one — the privacy policy
said so and now says the opposite. It is also the reason the site's text used
to move a moment after the page appeared: the fallback face is a different
width, so the first paragraph re-wrapped once the real one arrived. - The faintest text on the website — the footer, the small readouts above each
section, every table heading and the documentation contents list — is light
enough to read. It was the application's owntextFaint, which is 2.97:1
against the page and under what WCAG asks even of large text; in the
application it labels a meter you are already looking at, and on a phone in
daylight it was text you could not. The application's own interface still has
this and is not changed here. - ⌘O now opens a preset, and analysing an audio file has moved to ⌘I. The
layout is this application's document — the thing that is opened, saved and
sent to somebody — so it takes the chord every desktop user tries first, and
analysing a file is an import, which is what ⌘I means elsewhere.Saveon ⌘S
andSave as…on ⇧⌘S are both new. Ctrl on Windows and Linux, as always. - The preset browser is gone, and ⌘P with it. Saving is
SaveandSave as…;
the list of saved layouts is the presets folder in a file manager, which is
also where the delete button that used to be in that panel now lives.
Settings → Session still prints that folder and lets you select the path. - Whether a preset carries the delivery target and the skin is a property of the
preset now, rather than two switches beside a Save button: two rows in the File
menu, each asking whether the preset should carry one and ticked when it
does. They cannot go in the platform's save dialog — macOS would need a save
panel of our own, Windows a plugin of its own, and Linux cannot do it at all
— and as properties of the document they survive a save, which the
switches did not. - The plugin's window is drawn in the application's own palette and the
application's own two typefaces, both compiled into the VST3, the Audio Unit
and the Standalone rather than asked of the platform — so the panel looks the
same in Logic on a Mac as it does in Reaper on Windows, and looks like the
tool whose meters it is feeding. What it shows changed with it: a diagram of
the three places the path can break, with each run lit only while something is
travelling down it, and the socket's dashes moving while frames are actually
being sent, so a link that came up and quietly stopped no longer looks
identical to one that is working. The middle of that chain is the app icon
itself, drawn as line art in the shape macOS masks an icon with, so the thing
you picked out of the DAW's plugin browser and the thing in the diagram are
recognisably the same object. It also names the format it is loaded in and
the host it is loaded into, which are the first two facts on every bug report
and were the two nobody wrote down. - A dropped-frame warning in the plugin's window no longer erases the readings
it is a warning about. The count, the missing playhead and the loudness
reading shared one line, so the worst news arrived by deleting the evidence;
the readings now have a row of their own and the warning sits directly above
the Reset button that answers it. - The plugin's window says where the meters are when everything is working. A
metering plugin that draws nothing is a confusing object the first time
somebody inserts one — it loads, it reports itself healthy, and nothing
happens — and the line that was blank in exactly that case is the calmest,
most readable moment in the window. - The Super Meter's target tick is a plain mark again rather than one cut into
the arcs. 0.10.0 widened the slot beneath it to stand 1.5 px out either side,
which put a notch through all three rings at the target; the slot is back to
the tick's own width, so the rings run unbroken and only the tick crosses
them. 0.10.0's note describing the wider slot stands as written and is
superseded by this one. - Every menu in the application marks the value it holds with a check and a
band across the whole row. The band used to be the darkest colour in the skin,
which in Precision Instrument put a near-black hole in a menu that is itself
nearly black, and it stopped short of the menu's edges so the current value
read as a chip sitting in the list rather than as one of its rows. It is a
wash of the colour the rest of the interface already uses for selection now,
it reaches both sides, and the check says which row it is without anybody
having to compare two greys. Menus of actions — duplicate, rename, delete —
hold no value and are unchanged. - The iPad build no longer offers itself to iPhones. Its Xcode target had been
universal since the project was created, so a phone could install a
twenty-four-column canvas drawn for a tablet, and App Store Connect asked for
a set of iPhone screenshots of it. It is iPad-only now, which is what every
document already said it was.
🐛 Fixed
- The live analyzer's own document no longer offers itself to search engines as
oaa_analyzer_demo, described as "A new Flutter project.". It is the page the
front page loads into an iframe, and it had shipped as the Flutter scaffold
wrote it — no language, no viewport, and a title and description that
described the project worse than nothing would have. It now says what it is
and asks not to be indexed. - The website's 404 page no longer asks to be indexed, and no longer tells
crawlers that every address without a page is really/404. - "Linux dependencies" in the building document is a second-level heading, so
the page no longer skips from its title straight to a third level. - Re-saving a preset no longer silently drops the delivery target or the skin it
was carrying. The two switches in the preset browser reset to off every time
the panel opened and were never read back from the preset being saved, so
opening a layout that carried EBU R 128, moving one module and saving wrote a
preset that carried nothing — and nothing in the interface said so. They are
rows in the File menu now, and they are ticked from the preset itself. - The meters no longer freeze until you switch to another source. A capture
source that stopped delivering left the engine publishing an empty ring at the
same forty-seven frames a second for the rest of the session: every meter held
its last reading, the window and the menus stayed perfectly responsive around
it, RESET moved the readings to their floors and they held there, and
nothing anywhere said why. The engine now notices within a quarter of a
second, puts the source back itself when the format allows it, and says so on
screen; when only a new engine can follow the device, the application opens
one and the notice says the measure...
v0.10.1
⚡ Changed
- The name under the application's icon is Audio Analyzer on iPadOS and
Android, where it wasOAA. A home screen gives a label about eleven
characters before it starts dropping the spaces out of one, so the full name
has never fit there and the initials went in instead — which read as an
acronym nobody outside this repository knows. Nothing else is renamed: the
bundle identifier, the window title, the installers and the desktop builds
are untouched, so no permission grant moves with it.
🐛 Fixed
- The documentation site's sitemap names the eight documentation pages as well
as the front page. It had named the front page alone since before the manual
was part of the site, so nothing but the home page was being offered to a
search engine that asked. - The version on the site's download button is read from
pubspec.yamlat
build time.src/lib/app.mjswas written to do exactly that and then had no
importer at all — both pages still carried the number as text, so the button
was correct only for as long as nobody tagged anything.
🚧 Internal
- The site's demos replay what the engine measured instead of playing a mock.
website/tools/oaa_record/is a Dart CLI that links the real engine by FFI,
pushes forty-five seconds of a real track through it and writes down the
readings;website/tools/oaa_replay/holds that format andReplaySource,
a fourthMeterSourcebeside native memory, the socket a tablet reads and
the mock this replaces. Both Flutter targets play the same recording, so the
fourteen stills and the live canvas can no longer disagree about what the
material did — and no reading on the site is invented any more. The track is
CC BY 3.0 and is not in this repository:npm run recordrefuses to run
without the attribution filetool/fetch_test_audio.dartwrites, because the
licence asks for the credit wherever the audio is published, and the front
page carries it under the canvas. npm run checkinwebsite/opens every page at 360, 390 and 768 px with
the viewport actually overridden and fails if the document scrolls sideways,
naming the widest element rather than the overflow. It is the one responsive
defect that is invisible in a screenshot and obvious on a phone, and a
browser window cannot be dragged narrow enough to show it. Not part of
npm run build, because it needs Chrome.- The front page's hero is one column and a measure wide rather than two, and
the section rail in the manual tracks at 0.08em so that the longest heading
fits on one line in the 215 px it has. - Claude Code's
.claude/is ignored. Itssettings.jsonnamed a hook by an
absolute path inside one developer's home directory, which would have failed
silently on any other machine. - The website's tab icon survives a run of the icon generator.
packaging/icon/make_icons.dartwrote the app icon's tile over
website/public/favicon.svg, which is a different drawing on purpose — the
wave cropped out of the tile and stroked in the signal colour, because a tab
shows it at 16 px where the tile is mostly ramp. The hand-drawn version
therefore lasted until the next run of the generator and was reverted with no
error and no diff anybody read. The generator no longer writes that one file,
and says why where the line was. website/public/oaa.svgis back. It is the app icon's tile, written by the
generator, andscripts/og.htmlreferences it rather than holding a copy of
the mark; it was deleted in the change that redrew the logo while that
reference stayed, so the Open Graph card had been pointing at a missing file.website/AGENTS.mddescribes the directory as it is: the documentation pages
and the two lists that decide what they are, the live analyzer and the mock
the two Flutter targets share, and whytools/is outside the repository's
analyze gate. Its file table had been an inventory of a website that no longer
existed — three files it named were gone and eighteen it did not name were
there.CLAUDE.md,assets/AGENTS.mdandtool/AGENTS.mdno longer say that
tool/docs.dartrenders the documentation site. It renders one redirect per
page now, and the manifest it used to carry lives in
website/src/lib/docs.mjs.
v0.10.0
✨ Added
- A skin editor. Settings → Appearance → Edit skin opens all thirteen colour
roles with a picker on each, and the canvas behind the panel repaints as you
drag — as does a tablet mirroring the session. Every role prints its contrast
ratio against the surface it is read on, and the ones below the floor that
role is held to are marked with the reason; a low-contrast palette still
saves, because refusing to save what is already on screen is worse than a
warning. Skins remain plain JSON files and hand-editing them is unchanged. - Skins can be deleted from the editor, which previously meant finding the file.
- Reset, beside Edit on Settings → Meters → Delivery target, deletes every
target you have saved and puts the built-in six back. It asks first, in a
dialog naming what goes, and afterwards says how many files it removed.
Targets you wrote by hand are gone from the disk, so this is also how a
correction to a built-in is undone without going looking for its JSON file. - The VU Meter marks where the needle reached. A mark rides the scale at the
loudest point of the last second and a half and then falls back to the
needle, because a 300 ms movement is slow by design and the loudest moment of
a phrase is over before the needle has finished describing it. It is the same
quantity the needle draws, held rather than measured a second time. - The VU Meter prints its reading and its reference along the bottom of the
face: the deflection in VU on the left, and which dBFS level reads as 0 VU on
the right. The second one is the genuinely confusing thing about a VU meter
and the face now says it out loud. A module too small for either drops it and
keeps the dial. - The Spectrogram and the Oscilloscope can be drawn in full colour.
Colour: Full RGBin either module's menu replaces the skin's one-hue ramp,
and what it paints is the quantity that module's axes leave uncoloured. On the
Spectrogram that is the level: the spectrogram rainbow, indigo through
green and yellow to red and white, which separates far more steps of level than
one hue can. On the Oscilloscope it is the band balance, because a waveform
has no frequency axis at all: red, green and blue are its bass, its mids and
its highs, split at 200 Hz and 2 kHz, so a kick is red, a hat is blue and a
full-spectrum hit is white, the way DJ software has coloured audio for twenty
years. That balance is taken in decibels against the loudest of the three bands
rather than in power — bass carries an order of magnitude more power than air
does, and a power mix draws every piece of music red — and it is recorded with
the column, so the picture holds its colours instead of being repainted by
whatever is playing now. A column whose source published no spectrum keeps the
accent rather than being handed a colour that would claim a balance nobody
measured. Off by default in both, because a rainbow reads as more precise
than the measurement behind it, it collapses for the eight percent of men who
cannot separate red from green, and on the Spectrogram it brings its own dark
ground into a light skin. Nothing measured changes at either setting: no
reading, no report and no byte on the wire moves.
⚡ Changed
- A menu marks the value it holds by recessing that row, not by brightening
it. Every dropdown in the application — the delivery target, the signal
source, and a module's dozen settings — used to print its current value as the
lightest row in the menu, which put the emphasis on the one choice pressing
cannot change and left the options you can still take looking greyed out. The
chosen row now sits in a darker well and the alternatives sit on the menu's
own surface, which is how selection reads everywhere else in the interface.
Nothing about what the menus contain or choose changed. - The signal source in the status bar is a bordered chip, the same shape the
delivery target beside it has always had. It is the menu people open most and
it was drawn as a dot and a bare word in a row of bordered controls, which
reads as a caption rather than as something you can click. The dot stays,
inside the chip: bright while something is being metered, dim on Silence. - The
OAAwordmark is gone from the status bar. The window carries the
application's name; the bar carries what changes while you work, and three
capitals that never change were the one item in it saying nothing about the
signal. Every width at which the bar drops an item moved with it — the
controls at the narrow end now leave 25 to 40 px earlier than they did,
because a bordered chip cannot give back the width a bare word could. All of
them still have keyboard shortcuts except the three remote controls, which is
unchanged. - The sample rate no longer prints flush against the DAW's playhead. The gap
between the source group and the readings is a fixed one now rather than
whatever the window had left over, so it is there at every width instead of
only on a wide one. - The VU Meter has a face. The scale is a band along the rim rather than a
hairline arc, red above 0 VU over a tinted ring, and the needle is a taper
under a machined hub — so how far up the scale the programme is can be read
from the rim before the needle is read at all. Nothing about the movement,
the ballistics or the reading changed. - The Loudness Distribution fits its loudness axis to the programme instead of
always drawing −60 to 0 LUFS. A mastered programme's gated distribution
occupies eight to fifteen of those sixty decibels, so the picture the LRA
reading is taken from was squeezed into a fifth of the module with the rest
left blank; the axis now holds every occupied bin, the gated range and the
delivery target, rounds outwards to whole ticks, and stays where it is until
the distribution grows past it. No reading changes — the same bins are drawn
against a shorter stretch of the same scale.Scale: Full rangein the
module's menu restores the published axis, which is the one to pick when two
distributions are being compared side by side. - Open Audio Analyzer has a new logo, and every icon it ships follows it. A
white waveform on a teal ramp, replacing the four teal bars on graphite. The
app icon, the installers' icons, the Android launcher icon, the layered icon
macOS and iOS render, the favicon, the documentation site's header, the
README and the social card all change together. The tile is also a rounder
shape than it was, because the one macOS 26 and iOS 26 draw is rounder than
the one every version before them drew. Nothing about what the application
measures or displays is affected. - The icon reads less well at 16 px than the one it replaces, and that is a
real cost rather than an oversight. Four bars at four heights survived being
two pixels wide; a waveform with nine excursions across twelve pixels does
not, and no stroke weight rescues it. The line is held at one device pixel so
that it stays white instead of smearing to grey, and the sizes the icon is
now designed around are 32 px and up. Where this shows is the Windows
Explorer list view and a Linux panel at its smallest setting. - Precision Instrument and Daylight can no longer be replaced. A skin file
naming one of their two ids used to shadow the built-in; it is now ignored,
and the skin editor offers Save as new rather than an in-place save. The two
shipped skins are what proves the thirteen colour roles are semantic rather
than aliases for particular colours, and a reference point a file on disk can
quietly redefine is not one. If you had such a file it is inert now —
rename itsidand it comes back as a skin of its own. Delivery targets are
unaffected and still shadow their built-ins, because a target is a claim about
somebody else's published specification and has to be correctable without a
release.
🐛 Fixed
- The VU Meter no longer draws a needle for a reading nobody measured. The
per-channel arrays are NaN while a remote display's link to the host is
quiet, and the dial rested at the bottom of its scale with exactly the
confidence it reads a quiet passage with; the face now shows no needle and
the reading is an em dash. Only a tablet display could reach this. - The VU Meter's scale numbers no longer overprint each other on a small
module: −5 and −3 sit close together on a face that crowds towards the bottom
in voltage, and at the narrowest widths they collided into one smear. The
face now sheds the numbers it has no room for, keeping 0 and both ends. - A panel that scrolls draws one scrollbar rather than two. Settings, and
every other panel tall enough to scroll, carried the skin's own thumb on its
right edge and a second, wider grey one immediately inside it, which faded in
whenever the panel was scrolled. The second was supplied by Flutter, which
decorates a scrolling region on macOS, Windows and Linux without being asked;
the panel now declines it. Tablets never showed it. - The Super Meter's target tick sits in its slot again. The slot is a
surround laid down under the tick so that its contrast is identical on all
three rings, whatever each ring is currently drawing; it was being stroked at
exactly the tick's own width, so the tick covered it completely and was read
against the arc after all. It stands 1.5 px out either side now, which is what
the constant describing it always said. The tick itself is unchanged.
🚧 Internal
- The skin editor's suite waits for the effect of a save rather than for the
file. Its helper stopped as soon as the skin's file existed, which is one
event-loop turn before the editor is told the write finished — so the four
...
v0.9.0
📐 Measurement
- 7.1 material reads 0.35 LU quieter, and correctly. The +1.5 dB surround
weight was applied to every channel past the LFE, so a 7.1 stream had it on
the rear pair as well as the side pair. BS.1770 gives it to the surround pair
only — Report ITU-R BS.2217's channel table states 7.1 as
1.00 / 1.00 / 1.00 / N/A / 1.41 / 1.41 / 1.00 / 1.00 — and the ITU's own
two 7.1 compliance files read 0.35 LU high against a ±0.1 tolerance until this
was fixed; they now read −23.000 and −24.000 exactly. Only 7.1 and wider is
affected: mono, stereo, quad, 5.0 and 5.1 never reached the arm that was
wrong, and every reading from them is unchanged. Anything measured from a 7.1
master — itsLUFS-I,LUFS-M,LUFS-S,LRAand the delivery verdict
drawn from them — was 0.35 LU too loud and is worth re-measuring. Max MandMax Sare found on a 10 ms grid, where momentary and
short-term loudness previously advanced only every 100 ms. The official EBU
test vectors caught this: Tech 3341 tests 13 and 14 slide a 400 ms tone —
exactly one momentary window long — through twenty files in 20 ms steps and
requireMax Mwithin ±0.1 LU of −23.0 every time. On a 100 ms grid a tone
offset by anything else never lies inside one window whole, so sixteen of the
twenty read low, by up to 0.45 LU, and test 14 by 0.70. EveryMax Mand
Max Stherefore rises rather than falls: on the EBU's two authentic
programme segmentsMax Mrises by 0.16 and 0.11 LU andMax Sby 0.02 and
0.01, and a transient that fell between the old grid points can rise by up to
0.7 LU.LUFS-I,LRAand its percentiles,TP MaxandPeak Maxare
unchanged — identical to three decimals across all 70 files of the test set
— because both gating windows are still filed every 100 ms, which is the 75%
overlap BS.1770 asks for. Re-read a delivery decision that turned onMax M
orMax Sagainst a ceiling; one that turned on the integrated numbers stands.- The spectrum analyser draws its bands tilted, at 4.5 dB per octave by
default. The curve is rotated about 1 kHz, so 20 Hz is drawn 25.4 dB lower
than it measures and 20 kHz 19.4 dB higher — 44.8 dB between the ends of the
range, where previously the drawn level was the measured level at every
frequency. It is a view: the offset is added per band at the moment of
drawing, andSpectrumandSpectrum peakare published and sent over the
wire exactly as the engine measured them, so nothing needs re-measuring. What
changes is that a level read off the analyser's own dB scale is only true at
1 kHz now, which is why the module prints the tilt it is drawing at and why
Tilt: 0 dB/oct— where the scale is true everywhere — prints nothing. - The analyser's peak-hold line holds the drawn curve rather than the raw
bands. It is the highest the curve has been, held for a second and a half
and then let down at 12 dB a second, which is the schedule the engine's own
per-band hold already followed. Two consequences: the line moves with the
curve instead of jumping to a peak the curve is still easing towards, and on
Response: Slowit reads lower than it used to — by as much as the pole
smoothed the transient away — because the curve it is holding never went
there.Response: Fastholds every published frame and is the setting to
find a click with.Spectrum peakitself is unchanged. - The histogram draws both of its bands averaged over a second, where it
previously drew every 100 ms column exactly as measured.Smoothingin its
menu chooses Off — the old picture, byte for byte — Light at 0.5 s, Normal at
1.0 s or Broad at 2.0 s, and Normal is the default. The window is centred
rather than trailing, so nothing moves along the time axis; what it costs is
height on a short event. A transient the momentary band reached for a single
column now reads lower by roughly the distance between that column and its
neighbours — a 6 LU spike over a steady body reads about 1 LU above it on
Normal — and the newest column at the right edge lags the live meters by up to
half the window, settling as it ages. Nothing measured changes: the ring holds
the columns as they arrived, the smoothing is applied on the way out every
frame, and reports, the wire protocol and every other loudness module are
untouched. Choose Off to find the loudest 100 ms in a programme. - The loudness distribution's fill no longer double-draws itself. Each of
the 120 published bins was stroked half a pixel wider than its own spacing to
keep butt caps from leaving seams, so every overlap was composited twice
through the translucent gradient — a brighter line at all 119 bin boundaries,
and on a default-sized module nearly a fifth of the fill drawn at double
alpha. The bins are unchanged and none of them moves; what changes is that the
drawn area is now a shape rather than a row of overlapping lines, and a column
covering more than one bin takes the loudest of them rather than blending
them, the way the engine already maps transform bins into spectrum bands.
✨ Added
- The oscilloscope locks to the DAW.
Sync: Tempomakes the width a
musical division — 4 bars down to 1/32, straight, triplet or dotted — and
puts every sample in the column its position in the bar falls in, so each
pass overwrites the last in place and a kick is drawn in the same spot every
bar. The graticule divides into beats rather than tenths while it is locked,
and the corner says which division is on screen. It uses the host's own
playhead, tempo and time signature, which the plugin already forwards: MIDI
clock carries neither a bar position nor the accuracy, and is not involved.
A source with no playhead — a sound card, or a DAW that reports none — draws
the free window and labels it as the free window, because a display that
said1 barover something else would be worse than one that is not synced. - The spectrum analyser has a tilt,
Tiltin its menu: 0, 1.5, 3, 4.5 or
6 dB per octave, rotated about 1 kHz. Programme material falls with frequency
at something like 3 to 4.5 dB an octave, so an untilted analyser draws every
mix ever made as the same ramp — bottom octaves against the ceiling, top
octaves crushed into the floor — and spends most of its height on the one
part of the picture that carries no information. Tilted, a mix is roughly
horizontal and what is left is the deviation. The analyser prints the tilt it
is drawing at, because a dB scale quietly rotated across its width is worse
than no scale at all. - The oscilloscope draws a stereo signal either as two lanes or with both
channels around one centre line, fromStereoin its menu. Overlaid, the
two are told apart by weight rather than by colour, and the trace gets the
whole height of the module — which is the arrangement that shows what the
channels are doing differently. - The oscilloscope can be triggered by a transient.
Trigger: Transient
makes the display wait, armed, until the signal rises through a level you set,
draw forward across the whole width once from that sample, and hold what it
caught until the next crossing. It works at every time base — the roll above
200 ms is replaced by the sweep rather than left in place — so the attack of
one kick can be looked at instead of a picture that lands somewhere different
every pass.Trigger: Auto, which is the default and what the module did
before, is unchanged: a rising zero crossing below 200 ms, a rolling display
above it, and always something on screen. A threshold nothing reaches leaves
the last capture where it is, which is the mode working rather than failing.
Triggerstays in the module's menu underSync: Tempo, greyed rather than
dropped: a bar-locked window is placed by the bar line and has no use for it,
and a row that vanishes is a row somebody hunts for. - The oscilloscope's height and trigger threshold are sliders on the
module,HEIGHTandTHRESHOLDin a strip along the bottom of the plot,
and the threshold is drawn across the lane at the height it is set to. Both
are numbers over a wide range that are chosen by watching the waveform while
they move, and a menu that closes over the waveform on every step cannot be
used for that. The height goes from 1x to 32x, continuously rather than in
named steps — a reverb tail thirty decibels under full scale is a flat line at
1x, and the setting that fits the material is rarely a round multiple. The
strip is dropped on a module too short to spare the room, like the graticule
and the lane letters, and is not drawn on a remote display, which has no
layout to write to. Nothing measured changes: a sample is still marked as
clipped only if it reached full scale, and a trace that runs off its lane is a
trace that is zoomed. AUTObeside the threshold takes it from the loudest transient. It
follows the largest positive excursion of the mid signal over the last two to
four seconds — the quantity the trigger itself compares against — and sets the
threshold six decibels under it, which is half the amplitude and so still
inside the attack: the sweep starts before the transient rather than on top of
it, which is what a threshold set exactly at the peak would do. The slider
shows where the level has got to and stops answering while the box is checked;
unchecking it keeps the number Auto found rather than snapping back to
whatever was dragged before. Silence moves nothing — a passage nobody played
is not a measurement, and a threshold dropped to the floor would arm the
trigger on the noise underneath it.- The histogram has a
Smoothingsetting — Off, Light, Normal or Broad....
v0.8.0
✨ Added
- An Oscilloscope module: the waveform itself, in a lane per channel. Its
one control is a time base, from 5 ms to 5 s, and it sets both how much time
the width holds and how the window is found — below 200 ms the display is
triggered on a rising zero crossing, so a periodic signal stands still and
can be read, and above it the display rolls right to left the way a DAW
draws a waveform. Anything that reached full scale is drawn in the over
colour, so a clipped passage is a red band rather than a flat top somebody
has to notice. It measures nothing the previous thirteen modules did not:
the samples were already published, and it works on a tablet unchanged. - The oscilloscope leaves a gap where audio was measured and never published —
a file pushed through faster than real time, or a device that overran. The
alternative is drawing the samples that happen to be at hand across the
whole stretch, which is a picture of a programme that never played, at the
right amplitude and in the right place.
⚡ Changed
- The default layout's Spectrum tab carries the oscilloscope across its full
width. The analyser and the three displays below it are a row shorter each
to make room. A layout you have already arranged is untouched — the canvas
as you left it is what reopens.
🚧 Internal
- The meter clock now acquires the engine's snapshot on every tick and throttles
only the repaint. The frame-rate setting still does what it says — at 30 fps
the meters rasterise thirty times a second — but a measurement is no longer
lost between two of them. The engine's snapshot has one slot, so anything a
reader does not take before the next publish is gone; that cost the old
arrangement one measurement in three at 30 fps against a 47 Hz publish rate.
The oscilloscope is the first module for which that is a hole rather than a
coarser picture, and it reads the new unthrottled channel.
v0.7.0
✨ Added
- Pairing a display by camera. The sending machine shows a QR code under
the code button beside PUBLISH in its status bar, and a tablet reads it
under Scan a QR code on the screen it opens with. It carries the address and
the port and nothing else, so a display that scans one can still only watch.
This is the route that works where discovery does not — a venue or a guest
network that blocks multicast previously left somebody reading four numbers
off a laptop across the room and typing them into a tablet. - The pairing code names which network interface it is for, on a machine with
more than one. A laptop on Wi-Fi with a dock has two addresses and only one
of them may be reachable from the tablet, which is not knowable from the
sending side. - Scanning is offered on Android, iPadOS and macOS. Windows and Linux have no
camera implementation, so the row is absent there rather than present and
refusing; the typed address is offered on every platform, as before. - The macOS, Windows and Linux downloads now install the plug-in for you, with
a checkbox that starts ticked. macOS offers the VST3 and the Audio Unit as
separate rows, Windows and Linux the VST3; unticking leaves the application
on its own. Previously the plug-in was a bare archive and the instructions
for placing it by hand ran to a screenful, most of which existed because a
bundle in the wrong folder and a bundle that failed to load look identical
from inside a DAW. - A plug-in installed by the macOS package needs no
xattrstep. Files placed
by an installer are not quarantined, so the Gatekeeper refusal that has no
override — the one a DAW reports as "could not verify … is free of malware" —
does not arise. - The Windows installer registers an uninstaller under Settings → Apps, which
removes the plug-in as well as the application. - A third Linux download, a tarball, beside the AppImage and the flatpak. It
is the only one of the three that carries the VST3: unpack it and run
./install.sh, which needs no root and writes under your home directory
unless you ask it for--system. - The Linux tarball's
install.shis its uninstaller too, and takes--vst3,
--no-vst3,--systemand--uninstallfor use without a prompt.
⚡ Changed
- The remote display is reached from the status bar in one press, from
either end.REMOTEand the panel behind it are gone. In their place the
bar carries a PUBLISH switch, a button beside it showing the pairing
code, and ATTACH, which opens Show another machine directly. Publishing
no longer takes three presses and a question about which end of the link this
machine is — a question anybody pressing the button had already answered. - The remote display's name, port, update rate and pairing code are now in
Settings under Publish, with the rest of what the application remembers,
instead of in a modal of their own. The section also states whether it is
publishing and how many displays are attached, which the switch has no room
to print. - The name and port commit when the edit ends — on Enter or on leaving the
field — rather than from an Apply button. Nothing else in the settings panel
has one. - The pairing code's button is disabled, rather than absent, while publishing
is off. A code nothing is listening at is a display that scans, connects and
times out, which reads as a broken feature rather than as a switch that is
not on. - The pairing-code mark is redrawn on Material's
qr_codegeometry: three
finders and a scatter of data cells. The previous mark was five filled cells
in a 3x3 grid, which reads as a dice face. - A module's title bar and its corner resize grip now accept a finger from a
larger area than they draw: 40 px down from the top edge instead of the
24 px bar, and a 32 px corner square instead of a 16 px one. Both were well
under the 44 pt and 48 dp the platforms ask for, which made a module fiddly
to move and harder still to resize on a tablet. Nothing on screen changed
size, and neither did anything for a mouse, a trackpad or a stylus-free
pointer — the larger targets are admitted to touch and stylus only. - A tap on a module's resize grip selects the module. It previously did
nothing: the grip is opaque, so it took the tap from the module underneath
it and had nothing of its own to do with it. - A typed address that is not an address now says so, instead of the Connect
button appearing to do nothing. A mistyped port —192.168.1.20:70000— was
previously read as a host name with a colon in it and dialled, which failed
several seconds later as a name lookup, and an unbracketed IPv6 literal was
split at its last colon into a host and a port that could never connect. - The macOS download is an installer package rather than a disk image, and the
Windows download is an installer executable rather than an msix. Neither
original format can install a plug-in: a disk image has no install step at
all, and an msix's virtualised filesystem cannot write the shared VST3
directory. - The Windows installer is not yet signed, so Windows shows "Windows protected
your PC" and the user clicks More info → Run anyway. The msix it replaces was
refused outright when unsigned, so this is a state a user can get past rather
than one they cannot.
🐛 Fixed
- Publishing to a tablet no longer stops following the desk when the window
is narrowed. The status bar drops whole items rather than squeezing them,
and everything that fed the display host ran inside the item it dropped — so
past that width the socket went on streaming measurements while layout, skin
and delivery-target changes stopped arriving, and a changed name, port or
rate was never adopted. Nothing said so, and the tablet looked healthy
throughout. - The status bar no longer overflows its own row while publishing at narrow
window widths. The remote button's label grew fromREMOTEtoREMOTE · ON
when it was switched on — 27 px the width gate below it had never been
measured against, because the sweep that proves the bar fits never published.
The switch that replaced it is the same width in both states. - A warning that no display will find this machine no longer flashes on screen
for a second every time publishing is switched on. The first announcement of
a session is often refused before the multicast join settles and succeeds on
the next one a second later; the notice now waits for the responder's opening
burst to finish before it says anything, and clears immediately. - Publishing that could not start — the usual cause is a second copy of Open
Audio Analyzer already running — now says so on screen. The switch flicked on
and back off under the pointer with the reason recorded nowhere anybody was
looking. - A desktop that cannot announce itself on the network now says so, on the
Remote row and in the panel behind it, instead of reading Publishing while
no tablet ever lists it. The advertisement had no error reporting at all: its
bind error, its send error and its socket's error stream were all discarded,
and the last of those is the one a refused local-network permission arrives
on. Nothing about the machine looked wrong either, because the permission
blocks the announcement and not the port — a display given the address by hand
connected and worked perfectly throughout. - macOS users upgrading from 0.5.0 or earlier have to allow local network
access again. 0.6.0 changed the bundle identifier from
dev.openaudioanalyzer.oaatocom.openaudioanalyzer.oaa, and macOS keys the
permission to the identifier — so the entry granted to the old application no
longer applies to this one and tablets stop finding the desk. Allow Open Audio
Analyzer under System Settings → Privacy & Security → Local Network. Presets,
skins and paired hosts are unaffected; they are keyed by name, not by
identifier. - A panel now moves clear of a tablet's software keyboard. Every panel stayed
centred on the whole screen while the keyboard covered the bottom third of it,
so the address field in Show another machine — the last row above the footer —
was behind the keyboard together with the caret and everything typed into it.
Panels make room for the keyboard now, and the field being typed into is
scrolled in front of whoever is typing. - The DAW's playhead no longer floats loose in the middle of the status bar. Its
box reserves the width of a timecode, so a host that counts bars and beats
instead —1|1.0— filled a third of it and left the rest as a hole on the
right, while on the left the sample rate and channel count printed flush
against the reading at every window between about 1160 px and 1310 px. The
playhead now sits one gap from the elapsed clock it is read beside, and a
group's width away from the format readout at every window size. - A tablet's page tabs now sit beside the name of the machine they belong to.
The playhead was in front of them, and it reserves room for a timecode, a
tempo and a time signature whether or not the host at the other end keeps all
three — so on a host counting bars the tabs stood 88 px clear of the reading
with nothing between the two, and on one reporting a clock and no tempo 190 px,
reading as a control floating in the middle of the bar. The tabs come first
now, and nothing that appears, vanishes or reserves unused room can move them. - The Linux VST3 now loads on the same distributions as the Linux application.
It was built against a newer glibc than everything shipped beside it, so on an
older distribution it was simply absent from the DAW's plug-in browser with
nothing logged — indistinguishable from having installed it in the wrong
place. Aff...
v0.6.0
✨ Added
- macOS releases can be notarised, which is what lets a downloaded plugin or dmg
be opened with no further steps. A Developer ID signature now also carries the
hardened runtime and a secure timestamp, both of which Apple requires before it
will notarise anything and neither of which was being requested. - Tagging a release now builds the iPadOS display and uploads it to TestFlight,
so a tablet no longer has to be built from source to be updated. The upload
runs after the release is published rather than before it, which means a
TestFlight build always corresponds to a release that exists. The IPA itself
is deliberately not attached to the release: an App Store build provisions no
devices, so a downloaded copy could not be installed by anyone. - The iPadOS build declares that it uses no encryption. Without that declaration
every TestFlight build waits in "Missing Compliance" until somebody answers
the export question by hand, which is the one step an automatic upload cannot
take.
⚡ Changed
- The application identifier is now
com.openaudioanalyzer.oaa, and the
plugin's iscom.openaudioanalyzer.oaa.plugin. Both were underdev., which
reversed a domain nobody held; these reverseopen-audio-analyzer.com. The
hyphens do not survive the trip, and cannot: an AndroidapplicationIdand a
Kotlin package are Java identifiers and reject-, while Apple's
CFBundleIdentifieraccepts only letters, digits,-and.and so rejects
the_that Android would want in its place. Stripping them is the one form
that is legal on all six platforms. The Linux application id, the AppStream
and flatpak ids, the msix identity and the hicolor icon filenames all move
with it.
🐛 Fixed
- The macOS plugin bundles are built for Apple silicon and Intel, and load on
macOS 11 and later. Every release up to 0.5.0 shipped a bundle built for
whichever machine the release ran on — Apple silicon only, and requiring that
machine's own macOS version or newer — which a DAW reports in exactly the way
it reports a plugin that was never installed. - The instructions for a downloaded macOS plugin now describe what macOS 15 and
later actually do when the quarantine flag is still on it: a modal saying the
plugin cannot be verified free of malware, or that it will damage your
computer, with nothing in System Settings to override it — the "Open
Anyway" button there is only offered for a blocked launch, and loading a plugin
into a DAW is a library load. The fix has not changed and is still
xattr -dr com.apple.quarantine; what was wrong was the description of the
symptom, which called the failure silent and sent people looking for a
different problem. - The README no longer claims the macOS build is distributed "signed with a
Developer ID and notarised". It has never been either.
🚧 Internal
- CI imports a signing certificate before anything signs.
OAA_SIGNING_IDENTITY
was being handed tocodesignon runners whose keychain was empty, and
OAA_NOTARY_PROFILEnamed a credential that only exists on a developer's own
machine, so neither secret could have worked on a runner — and neither failed a
job, because they had never been set and the scripts took their no-credential
branches instead. packaging/ios/make_ipa.shandpackaging/ios/testflight.sh, and theipa
andtestflightjobs inci.yml. Manual signing is injected through
ios/Flutter/Release.xcconfigso the Xcode project stays on automatic signing
for local development; the script reads the signing authority back off the
archive, becauseflutter build ipaexits 0 on an export that silently fell
back to automatic signing.
v0.5.0
✨ Added
- Double-clicking the status bar on macOS zooms the window again, as
double-clicking a title bar does everywhere else on the Mac — the status bar
is this window's title bar, and it had answered nothing since 0.3.0. It obeys
the system's "double-click a window's title bar to" setting, so a Mac set to
minimise minimises and one set to do nothing does nothing, and it waits the
double-click interval that Mac was configured with. No control in the row
answers any later for it: what Flutter recognises there is still a single
click, and the pair is counted in the runner.
⚡ Changed
- The iOS and Android home screen label is
OAA, the wordmark the status bar
already draws. It wasOpen Audio Analyzer, which no tablet ever actually
showed: iOS fits an icon label to the width of one icon by tightening the
tracking before it truncates, and tracking is spent on the spaces between
words first — a 19-character name arrived on the home screen as
OpenAudioAnal…, run together and cut short anyway. Apple's guidance is
twelve characters. The product's name is unchanged everywhere it fits: the
macOS, Windows and Linux applications, both permission prompts, and every
configuration directory — nothing a tablet has saved moves.
🐛 Fixed
- The canvas no longer gets slower the longer a spectrogram is on screen. The
spectrogram redrew its whole history as run-length marks on every published
frame, and its cost was budgeted against smooth columns — real material
jitters a brightness step between most adjacent rows, so a large display was
re-recording and re-rasterising 150,000–230,000 marks about 47 times a
second, a cost that ramped for the half-minute the history took to fill after
a mount and then stayed. Every meter repaints from the same clock, so it
dragged the whole canvas — most visibly the analyser — and the remote display
paid the same price on weaker hardware, more of it at the 60 fps link rate.
The history is now kept as pixels and drawn as one image, a quarter of a
millisecond per published frame whatever the signal does; the numbers are in
tool/bench_spectrogram.dart. - On a remote display, the tab control now sits beside the name of the machine
being watched instead of stranded in the middle of the link bar. The bar kept
room for the host's playhead whether or not the host had one, so on every host
with no DAW behind it — a desktop metering a device or a file, which is most
of them — 248 px of nothing stood between the name and the tabs. The slot
appears with the playhead and does not move again while the link lasts, so a
reading that goes stale does not shift the tabs out from under your finger.
🚧 Internal
tool/bench_spectrogram.dartis formatted the way the test job's
dart format --set-exit-if-changedstep demands. It was not, so that job
failed on every push after the benchmark landed while the analyzer, the
suites and the benchmark itself all stayed green. That step is now listed
with the other gates inREADME.mdandCLAUDE.md, which is why it was
never run by hand.
v0.4.1
🐛 Fixed
- The macOS plugin bundles now carry a valid code signature. All three — the
VST3, the Audio Unit and the Standalone — shipped with an invalid one in every
release up to 0.4.0: the VST3's resource seal was computed before JUCE wrote
moduleinfo.jsoninto the bundle, and the other two were never bundle-signed
at all. On Apple Silicon that is enough for a DAW to leave the plugin out of
its browser without logging anything, and forauvalto refuse the Audio
Unit. Each bundle is now signed after everything that writes into it and
verified on the spot, so the build fails rather than producing a bundle it
cannot verify.auval -v aufx OaaM OaaApasses. If the plugin never
appeared in your DAW, this is why — and on macOS also strip
com.apple.quarantinefrom a copy you downloaded, which no build can do for
you.
✨ Added
- The documentation site's Install
page now has an In a DAW section: which folder the VST3 and the Audio Unit
have to be copied into on each platform, thexattrline that a downloaded
copy needs on macOS, and the Ableton Live preference that has to be on before
Live looks in the folder at all. The page had linked to that section since the
site was first published, and the section did not exist.
🚧 Internal
OAA_CODESIGN_IDENTITYsigns the macOS plugin bundles with a Developer ID
instead of ad-hoc. Releases stay ad-hoc.- Signing runs from a target that depends on the format target rather than from
POST_BUILD, which is not last: aMACOSX_PACKAGE_LOCATIONresource is
copied by a sibling rule that make may run after the link, and on a
from-scratch build it does. Only visible with the bundle deleted first.
v0.4.0
✨ Added
- An Android tablet now finds hosts on the network by itself, like every other
platform. It held a multicast socket that never received an answer, because
Android's Wi-Fi driver discards multicast for an app that is not holding a
WifiManager.MulticastLock— silently, with the search still saying it was
looking. The lock is held while a search is running and given back when it
stops, so it costs nothing once a display is attached. - An Android tablet now remembers its layout, its skin and the host it was last
attached to. Nothing in an Android process names a directory it may write to,
so the configuration directory is asked for over a platform channel and lives
in the app's ownfilesdirectory; every launch before this one started from
the defaults. - Metering your Mac's own output no longer needs a loopback driver. On macOS
14.2 and later, System Output is the first entry in the source menu, named
after the output device it is metering. It is a Core Audio process tap, so
there is nothing to install, nothing to reroute and no password prompt — the
audio still reaches your speakers while it is being measured. macOS may ask
for permission to record system audio the first time. Below 14.2 the entry is
absent and BlackHole or Loopback is still the answer; Windows and Linux are
unaffected, since WASAPI loopback and a PipeWire monitor source already appear
in the list.
⚡ Changed
- The wire protocol is at version 3, and a receiver now accepts any version it
knows rather than only its own. A plugin built against 0.3.0 keeps working
with a newer app, which under the old equality check it would not have: a
plugin lives in the DAW's plugin folder and stays there across app upgrades,
so the mismatch was the ordinary case, and what it looked like from the plugin
was a port that accepts and hangs up forever — indistinguishable from the
defect where the port was never bound at all. The rule is one-way on purpose:
a peer newer than this build is still refused, because a later version may
have moved a table and misreading a measurement table is how a meter draws a
confident wrong number. A tablet still running 0.3.0 or earlier will refuse
a newer desktop and say so, rather than drawing anything; update both ends.
Version 3 adds a frame type and moves no byte of any existing table — held by
a test that decodes the frozen version-2 golden and diffs it against the
version-3 one, where exactly four bytes differ and all four are version
fields. - A host search that is running but cannot receive says so instead of
"Looking for hosts on this network…", which is the face a search that is about
to succeed wears.
🐛 Fixed
- The plugin's status panel no longer claims a playhead from a host that is not
giving one. The line was drawn from whether a transport had ever been
published, and the plugin publishes one for every audio block — the empty one
that means "this host said nothing" included — so it read as a playhead the
moment audio started flowing, on precisely the host it exists to warn about.
It now follows what the host is reporting now, and says "no playhead from
host" again if a host stops.
🚧 Internal
- Groundwork for the Elapsed and Timecode LUFS modes, which are not yet
offered by any module — this is the protocol and the engine underneath them,
and the modules and their menu are the change after this one.docs/WIRE.md
gains0x0020 SET_LUFS_MODE, the first frame that travels from consumer to
producer, permitted on the ingest port only because that one binds loopback
where whatever connects is already running as this user; the display port
binds every interface and stays read-only until somebody designs
authentication for it. Three implementations moved together, as that file
requires. - The engine can reset itself when the signal returns after a silence
(oaa_engine_set_silence_reset, ABI 5), which is what the System mode is made
of. It lives inengine/rather than above it because silence is a property
of audio and not of a host — one implementation serves a plugin and a sound
card, where two would eventually disagree about when a track began. The gate
runs before the block it judges, so a track whose loudest sample is in its
first block keeps that peak rather than having it cleared by its own reset.
Off by default, and off for file analysis, which must measure a file whole.
The two transport-driven modes need no engine API at all: they are the
producer declining to push, soengine/still does not learn what a DAW is. - The plugin's answer to a host that supplies no transport is now held by a
test.plugin/test/transport_capture_test.cpphosts theAudioProcessor
directly, which is the only way to reach either of the two branches behind it:
no VST3 or Audio Unit host can express "no playhead" or "no position", so
neither a DAW nor the fake DAW can ask for them. It runs in the gated plugin
job'sctest, and both it and the transport box's own test were verified by
breaking the code under them and watching them fail. - Five documents caught up with protocol version 3's two goldens.
docs/WIRE.md
still gave the SNAPSHOT payload size "at protocol version 2" in the one
document whose header declares version 3;packages/oaa_wire/AGENTS.mdnamed
wire_v2.binas the golden its codec test decodes, when the test reads both
andwire_v3.binis the one tracking the current serialiser; and two comments
inci.ymlcredited the C++ producing side with writingwire_v2.bin, which
it no longer does. The one that could have cost something: the regeneration
command inplugin/test/wire_fixture.cppstill wrote towire_v2.bin— the
frozen file whose whole purpose is to hold bytes produced before version 3
promised to move no table. Following it would have destroyed the evidence and
left every test green. - Two claims about that branch are corrected here rather than in the 0.3.0
notes, which are released. It is not reached by the Standalone build —
JUCE 8'sAudioProcessorPlayerinstalls a counting playhead whenever the
processor it is given has none — and it is unreachable through an Audio Unit
as well, not only through VST3. The plugin's own handling was correct
throughout; only the note about what exercised it was wrong.README.mdno
longer lists it under Known gaps, because it now has a test instead of a
paragraph.