Fold soundThing's changes back down, and expose the two new switches
The three changes that went up came back as part of soundThing, along with two more that they made possible. The engine here is now b73e5c0 character for character, except that em-dashes and arrows in comments are written as ASCII because this tree is ASCII only - a local rule, not an improvement, and not sent up. So synth.h's "what was changed" list is gone. There is nothing to list: what has to be kept current is only that if either copy changes, the other one has to be told. ---- What came back ---- A VOICE CAN END ITSELF. Naming the level's source said what shapes a voice; nothing said what ends one, so the only thing that could ever finish one was a key coming up. A game is nearly all one-shots and not one of them wants its length decided by how long a note was held. Exposed as parameter 0x51: 0 gated, 1 triggered. AND A ONE-SHOT IS THE SAME ONE-SHOT TWICE. A triggered voice re-arms its oscillators, and an LFO can be told to start over with each voice - parameter 3 of either LFO. Both halves are needed and the check proves it: with the LFO left free, two triggered hits still differ. Their note warned that whatever applies a patch to a channel has to set these or they hold synthInit's defaults. Checked: Voyager never calls synthSyncVoices, so their 0001 is a no-op here as they predicted, and nothing reaches into an LFO's phase, so the struct split is safe. ---- What it is for ---- Lander's crash is a triggered voice now, so boomOff is gone. Nothing has to remember to end a bang. SoundPatch learnt voice_levelSource, voice_gate and lfo<N>_mode, which the new soundThing writes - without that it would have refused every patch saved from it, since an unknown field stops the tool on purpose. A patch from before those fields still converts, and says in its own comments that it predates the level routing. Three checks, each seen to fail on its own break: a gated voice still sounding with nothing holding it, a triggered one down to nothing with no gate ever dropped, and two hits identical sample for sample. One test bug worth keeping: the first version of the repeatability check struck the second note while the first was still ringing, so what it found and compared as "the second hit" was a point in the middle of the first one's tail. It now looks for sound after SILENCE rather than sound after an offset.
This commit is contained in:
@@ -103,9 +103,19 @@ static const Mapping mappings[] = {
|
||||
{ "lfo0_active", 0x60, AS_BOOL, 0, 0, "LFO 0, on" },
|
||||
{ "lfo0_waveform", 0x61, AS_DIRECT, 0, 0, "waveform" },
|
||||
{ "lfo0_rate", 0x62, AS_EXPONENTIAL, 0.05, 20.0, "rate, in hertz" },
|
||||
{ "lfo0_mode", 0x63, AS_DIRECT, 0, 0, "0 free, 1 starts with a voice" },
|
||||
{ "lfo1_active", 0x70, AS_BOOL, 0, 0, "LFO 1, on" },
|
||||
{ "lfo1_waveform", 0x71, AS_DIRECT, 0, 0, "waveform" },
|
||||
{ "lfo1_rate", 0x72, AS_EXPONENTIAL, 0.05, 20.0, "rate, in hertz" },
|
||||
{ "lfo1_mode", 0x73, AS_DIRECT, 0, 0, "0 free, 1 starts with a voice" },
|
||||
|
||||
// ---- The two that are about the voice as a whole ----
|
||||
//
|
||||
// soundThing gained a field for each of these at the same time the engine did. A patch
|
||||
// written before that has neither, which is why the level source has a default below: it
|
||||
// was always envelope 0 when there was nothing to say otherwise.
|
||||
{ "voice_levelSource", 0x50, AS_DIRECT, 0, 0, "what shapes the level" },
|
||||
{ "voice_gate", 0x51, AS_DIRECT, 0, 0, "0 gated, 1 triggered" },
|
||||
};
|
||||
#define MAPPING_COUNT ((int)(sizeof(mappings) / sizeof(mappings[0])))
|
||||
|
||||
@@ -194,12 +204,23 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---- A patch from before the level could be routed ----
|
||||
//
|
||||
// Those files have no voice_levelSource, and what it meant there was always envelope 0.
|
||||
// Said out loud rather than left out, because a channel keeps its patch between notes and
|
||||
// would otherwise carry a previous one's routing into this one.
|
||||
int levelIndex = -1;
|
||||
for (int i = 0; i < MAPPING_COUNT; i++) {
|
||||
if (mappings[i].parameter == 0x50) { levelIndex = i; break; }
|
||||
}
|
||||
int assumedLevel = (levelIndex >= 0 && !seen[levelIndex]);
|
||||
if (assumedLevel) {
|
||||
values[levelIndex] = 1; // MOD_SOURCE_AMP_ENV
|
||||
seen[levelIndex] = 1;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAPPING_COUNT; i++) if (seen[i]) count++;
|
||||
// The level routing is soundThing's one blind spot: it has no field for it because there
|
||||
// it is always the amplitude envelope. Said out loud here so a channel that was left set
|
||||
// some other way by a previous patch does not carry it into this one.
|
||||
count++;
|
||||
|
||||
FILE *out = stdout;
|
||||
if (argc > 3) {
|
||||
@@ -215,11 +236,11 @@ int main(int argc, char **argv) {
|
||||
fprintf(out, "#Data\n\n");
|
||||
fprintf(out, "%s:\n", label);
|
||||
fprintf(out, " 0d%-24d; how many pairs follow\n", count);
|
||||
fprintf(out, " 0x50 0x01 ; the level is the amplitude envelope\n");
|
||||
for (int i = 0; i < MAPPING_COUNT; i++) {
|
||||
if (!seen[i]) continue;
|
||||
fprintf(out, " 0x%02X 0d%-3d ; %s\n",
|
||||
mappings[i].parameter, values[i], mappings[i].note);
|
||||
fprintf(out, " 0x%02X 0d%-3d ; %s%s\n",
|
||||
mappings[i].parameter, values[i], mappings[i].note,
|
||||
(i == levelIndex && assumedLevel) ? ", which this patch predates" : "");
|
||||
}
|
||||
if (out != stdout) fclose(out);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user