tools: Add volume adjustment function.
3 files changed, 37 insertions(+), 0 deletions(-)

M res/resources.json
M tools/audio.js
M tools/resources.js
M res/resources.json +1 -0
@@ 3,6 3,7 @@ 
 	"opnbFrequency": 8000000,
 	"opmFrequency": 3579545,
 	"waitThreshold": 50,
+	"attenuation": -6,
 	"tracks": [
 		{
 			"name": "01",

          
M tools/audio.js +34 -0
@@ 169,6 169,19 @@ class AudioTrack {
 		return track;
 	}
 
+	attenuateVolume(dB) {
+		checkTypes(arguments, "number");
+		const track = new AudioTrack(this.name);
+		for (const command of this.commands) {
+			if (command instanceof AudioCommandFMInstrument) {
+				track.addCommand(command.attenuateVolume(dB));
+			} else {
+				track.addCommand(command);
+			}
+		}
+		return track;
+	}
+
 	frequencyBeforeKeyOn() {
 		const track = new AudioTrack(this.name);
 		let lastCommand = null;

          
@@ 457,6 470,27 @@ class AudioCommandFMInstrument extends A
 		super(channel);
 		this.parameters = parameters;
 	}
+
+	attenuateVolume(dB) {
+		checkTypes(arguments, "number");
+		const instrument = new AudioCommandFMInstrument(this.channel, this.parameters.slice(0));
+		switch (instrument.parameters[24] & 7) {
+			case 7:
+				instrument._attenuateOperator(0, dB);
+			case 6:
+			case 5:
+				instrument._attenuateOperator(1, dB);
+			case 4:
+				instrument._attenuateOperator(2, dB);
+			default:
+				instrument._attenuateOperator(3, dB);
+		}
+		return instrument;
+	}
+
+	_attenuateOperator(operator, dB) {
+		this.parameters[4 + operator] = Math.min(Math.max(Math.round(this.parameters[4 + operator] - dB * 8 / 6), 0), 127);
+	}
 }
 
 class AudioCommandWait extends AudioCommand {

          
M tools/resources.js +2 -0
@@ 62,11 62,13 @@ class ResourcesLoader {
 			const track = await new VGMLoader(jsonTrack.name, trackPath).loadTrack();
 			const waitThreshold = "waitThreshold" in jsonTrack ? jsonTrack.waitThreshold : json.waitThreshold || 0;
 			const channelMapping = "channelMapping" in jsonTrack ? jsonTrack.channelMapping : json.channelMapping || [0, 1, 2, 3, 4, 5, 6, 7];
+			const attenuation = "attenuation" in jsonTrack ? jsonTrack.attenuation : json.attenuation || 0;
 			return (track
 				.moveWaitAfterLoop()
 				.removeWaitsUnder(waitThreshold)
 				.toFMCommands()
 				.mapChannels(channelMapping)
+				.attenuateVolume(attenuation)
 				.frequencyBeforeKeyOn()
 				.trimLeadingSilence()
 				// .quantise(60)