Repository navigation
Uploads converted for the pedal: mark them on purpose, and say what changed - #153
Merged
Merged
Conversation
push named the file on the card after whatever path it was handed, so the working name of a conversion's temp file travelled to the card by accident. PushOptions now carries an optional landed name; the core checks it before a byte moves — a bare file name, something in front of .wav, no separator in either direction — and refuses otherwise with the slot and the archive untouched. Absent, the handed file's own name, as before.
…eferences The suffix on a rebuilt upload becomes a decision: uploadmark::landedName gives <source stem><suffix>.wav for a conversion and leaves an untouched file's name alone, and a suffix with a character a FAT name cannot hold is refused by name rather than stripped. The default stays -pedal, the spelling existing cards already carry. ImportPrefs gathers the three upload preferences — the normalize switch, its target and the mark — with one reader and one writer over the PropertiesFile, so the dialog, the push job and a test see the same keys and defaults. A mark cleared to nothing stays nothing: the key is present, its value empty.
wavimport::prepare wrote <stem>-pedal.wav into import-tmp, renamed around a clash, and left the caller to delete the file by hand on both exits of the push. The conversion now goes to a directory of its own under import-tmp, owned by the Prepared through a RAII handle: gone when the job returns and when it throws alike, and two uploads with the same stem in one queue never meet. Prepared also reports the source's sample rate, sample format and channel count. A compressed source names its codec, because the float32 our MP3 reader hands out is the decoder's, not the file's. describeConversion says only what differs from the pedal's 44100 Hz, 32-bit float, stereo — so a loudness-only rewrite of a pedal-ready file has no sentence at all.
…nged The push job reads the upload preferences when the player acts, names the file on the card through the mark rule, and hands that name to push instead of inheriting the temp file's. The note the toast and the history row carry opens with the conversion's facts, joined to the normalization sentence when both apply, and the operations log line says the landed name when it differs from the source's. Settings -> Import gains the mark field under the normalize switch. A character a FAT name cannot hold snaps the field back to the stored mark and says why beneath it; nothing is stripped on the way in.
Why a rebuilt upload lands as <name>-pedal.wav, what the push report says about it, and where the suffix lives.
describeConversion joined its two sides with an ASCII "->" while describeNormalize, which shares the same note, draws U+2192. A push that was both rebuilt and levelled read with two different arrows in one sentence. The conversion now uses the same escape, the tests pin the sentences with it, and the guide's example matches what the toast shows.
…old take moves push archives and removes the old take before it writes the new one, so a name the card refuses at the write leaves the slot folder empty under a config that says it holds audio. The up-front check had no length rule, and a converted upload's <stem><mark>.wav could pass it at 256 UTF-16 units and fail on the card (review of #139: a 252-character stem with force, a 247-character stem through the whole job, a 260-character mark). FatName.hpp now owns what a file name on the card may be — FAT's reserved characters and control range, the 255-unit limit counted in UTF-16 units from the UTF-8, and the device names Windows will not open, judged before the first dot as Windows judges them — so the core and the app check the same rules. assertLandedName refuses all of it before a byte moves, and with it a name the card's own sweep would delete ("._take.wav" was reported as pushed and then swept) and a name starting with a dot. The reproductions leave the card byte-identical and the old take in place.
A float DAW export wearing a WAVE_FORMAT_EXTENSIBLE header fails the pedal's strict gate and goes through the converter, so it landed as <stem>-pedal.wav with an empty sentence although no sample moved. "Rebuilt" is now a fact Prepared reports: the rate, sample format or channel count differed from the pedal's, or a gain went in. The mark keys on it; a header-only rewrite lands as <stem>.wav — the extension still changed on purpose — with no mark and no sentence, and its samples equal the source's bit for bit. `converted` keeps meaning what it did: the file lives in the job's directory. landedName takes what happened to the audio (untouched, repackaged, rebuilt) and judges the mark only where it is used, so a mark hand-edited into the settings file no longer stops an untouched upload. A name it builds over the FAT limit is refused with the name it would have been, never trimmed, and assertSuffix carries a named cap so the Settings field refuses a mark no name could carry. The field trims: a mark of only spaces is the empty mark the hint promises. FLAC keeps its samples' width and JUCE's reader reports it, so a FLAC source reads "24-bit" like PCM; only MP3 and Ogg Vorbis name their codec. A job directory that will not delete leaves a line in the operations log — the only trace a leftover has until something sweeps import-tmp. The ImportPrefs comment now says what the code does: the preferences are read as the job is queued and travel with it.
The guide says the push toast and the history row spell out what changed, but the push row drew only the take's name, length and tempo; the job's note was stored and never shown. The row now draws the note's sentences after the numbers — the rebuild's facts, the normalization's — leaving the note-length fact to the place it already had at the end.
…ice names FAT's 255 units was not the binding limit: the card is read on Windows, where a path is capped at MAX_PATH — 260 characters, terminator included — unless the host opted into long paths, which neither JUCE nor this app declares. The card folder "E:\ROLAND\WAVE\001_1\" is 21 characters, so a name of 239 to 255 units passed every check and brought back the outcome the last round fixed: archive, remove, fail at the write. The cap is now 238 on every platform (the same card meets every host), with the arithmetic in FatName.hpp; 238 passes, 239 is refused, before a byte moves. Windows also reserves COM and LPT with the superscript digits 1-3 (U+00B9, U+00B2, U+00B3); isDeviceName now takes those as the digit.
readWavInfo refuses a truncated file along with every other malformed one, so an importer could not tell "cut short" from "not a WAV" without reading the message. isTruncatedRiff says that one thing — the chunks claim more bytes than the buffer holds — so the import can refuse to pad it.
"Repackaged" was decided on reader facts that can lie. On macOS
registerBasicFormats adds CoreAudio, which takes any WAV JUCE's own reader
refuses — float64, mu-law, anything over 32 bits — and always reports
32-bit float, so a float64 export read as "nothing differs" and landed
unmarked, with no sentence, with every sample re-quantised. Positive
evidence only, now: a source is repackaged only when a reader that reads
samples as they lie (JUCE's WAV, AIFF and FLAC readers) reports the pedal's
own shape and no gain went in; anything a decoder made is rebuilt, and the
sentence says what it can — "decoded by the system → 32-bit float", or the
codec. CoreAudio stays registered: dropping it would lose AAC and M4A.
The readers are told apart by the name the READER gives itself, not by the
format object that was asked: WavAudioFormat hands an Ogg stream inside a
WAV to the Ogg reader, which the old dynamic_cast missed ("16-bit float →
32-bit float"). The mp3 reader's name is a constant of its format now.
A WAV whose header claims more frames than the file holds is refused with
its name, never padded: JUCE fills the missing frames with silence, and the
pedal would have got a loop twice as long as its audio under the player's
own name.
The mark's cap derives from the card's limit, so it follows the 238 of FatName.hpp: 233 units at most, leaving the extension and one character of name. A whitespace-only mark hand-edited into the settings file still landed a "song .wav"; importprefs::read trims it as the Settings field does, so "only spaces is the empty mark" holds whichever hand wrote the file.
HistoryRecorder::finish stores a failed operation's error as its note, and the push row had started drawing every note as the job's own words — a refused push read "take.wav - slot 9 already has audio". story::Facts carries the operation's status now, and the sentences are drawn only for one that finished; a failed or interrupted row keeps the shape it had.
isTruncatedRiff flagged any chunk past the end and said nothing else, so a complete recording with a cut LIST trailer read as "cut short" alongside a data chunk missing half its bytes, and a header a writer never finalised (data size 0xFFFFFFFF) read as claiming four gigabytes. riffFault names the fault as a clause for the importer: a data chunk short of its claim by how many bytes, a size never set, two data chunks, two fmt chunks, a short fmt chunk, no data or no fmt chunk. A metadata chunk cut off after a complete data chunk costs no sample and is no fault. The fmt fields themselves are shape, not structure: an extensible tag is for the converter and the gate.
prepare took every refusal of the core's gate as a reason to convert, so a WAV with two data chunks — refused by the core as malformed — went to JUCE's reader, which kept the last chunk and dropped the first, and the file landed unmarked under the player's own name with 88200 frames gone (third review of #139). A structural fault is now refused with the fault named, before any reader sees the file; what the gate then refuses is the header's shape, and that is the converter's job. A recording whose cut trailer is its only flaw is imported as a repack, every sample intact; a data chunk short of its claim and a header never finalised are refused by those names.
importprefs::read trimmed a stored mark, so " pedal" read as "pedal" — against the rule UploadMark.h states, that a rewritten mark is a different mark. One rule now, markAsTyped, shared by the Settings field and the reader: a mark of only whitespace is the empty mark the hint promises, and every other mark keeps its spaces before, inside and after, as typed; the field writes back what it accepted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #139.
A file the pedal cannot take as-is was rebuilt into
import-tmp/<stem>-pedal.wav, andpushnamed the file on the card after the temp file it was handed, so the-pedalsuffix reached the card by accident. The mark is worth keeping (the bytes in the slot are not the bytes of the player's file), so it becomes a decision.-pedal; clearing it turns the mark off. Stored beside the other upload preferences (app/ImportPrefs.h, one reader and writer for the dialog and the push job; read when the player acts, as the normalize preference already was).app/UploadMark.h,PushOptions::landedName): a rebuilt upload lands as<stem><mark>.wav(an importedsong.mp3becomessong-pedal.wav), an untouched one keeps its name, and a file whose header alone was repacked (an extensible float32 DAW export, every sample intact) lands as<stem>.wavwith no mark. The conversion goes to a directory per job that dies with the job, success or throw.core/include/loopercat/FatName.hpp,assertLandedName): a name the card or a host could not hold (separators, FAT-reserved and control characters, more than 238 UTF-16 units so the Windows path fits MAX_PATH, Windows device names including the superscript digits, names the card sweep deletes, names starting with a dot). Before this, a long name passed the checks,pusharchived and removed the old take, and the write failed, leaving the slot empty.wav::riffFault): two data chunks, a cut data chunk, a header never finalised. A cut metadata trailer after complete audio still imports..wavis now refused ("must end in .wav") instead of landing unindexable.Docs: the guide's "Moving audio" section explains the mark and where to turn it off.
Tests:
upload_mark_tests77,fat_name_tests108,import_prefs_tests28,wav_tests90,wav_import_tests230,commands_tests1630 (the landed name on the card, every refusal on an empty and an occupied slot with the card byte-identical afterwards),slot_story_tests84,mp3_import_tests27. Non-GUI ctest 59/59; the six GUI harnesses 6/6 locally.Follow-ups noted, not in this PR: a startup sweep of
import-tmpafter a crash (a failed delete is logged);pushstill archives and removes the old take before writing the new one, so a write failure the checks cannot foresee (disk full) leaves the slot empty; the Settings field has no automated test (no settings harness); Windows narrow-path handling of non-ASCII names is pre-existing and to be tried on the Windows box.