Skip to content

Commit d010f5c

Browse files
committed
Added an option for layered instruments in a single channel.
1 parent be84d20 commit d010f5c

File tree

12 files changed

+1110
-646
lines changed

12 files changed

+1110
-646
lines changed

editor/ChannelSettingsPrompt.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ import {HTML} from "imperative-html/dist/esm/elements-strict";
55
import {SongDocument} from "./SongDocument";
66
import {Prompt} from "./Prompt";
77
import {ChangeGroup} from "./Change";
8-
import {ChangePatternsPerChannel, ChangeInstrumentsPerChannel, ChangeChannelCount} from "./changes";
8+
import {ChangePatternsPerChannel, ChangeInstrumentsFlags, ChangeChannelCount} from "./changes";
99

10-
const {button, div, h2, input} = HTML;
10+
const {button, div, br, h2, input} = HTML;
1111

1212
export class ChannelSettingsPrompt implements Prompt {
1313
private readonly _patternsStepper: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "number", step: "1"});
14-
private readonly _instrumentsStepper: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "number", step: "1"});
1514
private readonly _pitchChannelStepper: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "number", step: "1"});
1615
private readonly _drumChannelStepper: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "number", step: "1"});
16+
private readonly _layeredInstrumentsBox: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "checkbox"});
17+
private readonly _patternInstrumentsBox: HTMLInputElement = input({style: "width: 3em; margin-left: 1em;", type: "checkbox"});
1718
private readonly _cancelButton: HTMLButtonElement = button({class: "cancelButton"});
1819
private readonly _okayButton: HTMLButtonElement = button({class: "okayButton", style: "width:45%;"}, "Okay");
1920

20-
public readonly container: HTMLDivElement = div({class: "prompt noSelection", style: "width: 250px;"},
21+
public readonly container: HTMLDivElement = div({class: "prompt noSelection", style: "width: 250px; text-align: right;"},
2122
h2("Channel Settings"),
2223
div({style: "display: flex; flex-direction: row; align-items: center; height: 2em; justify-content: flex-end;"},
2324
"Pitch channels:",
@@ -28,12 +29,20 @@ export class ChannelSettingsPrompt implements Prompt {
2829
this._drumChannelStepper,
2930
),
3031
div({style: "display: flex; flex-direction: row; align-items: center; height: 2em; justify-content: flex-end;"},
31-
"Patterns per channel:",
32+
"Available patterns per channel:",
3233
this._patternsStepper,
3334
),
3435
div({style: "display: flex; flex-direction: row; align-items: center; height: 2em; justify-content: flex-end;"},
35-
"Instruments per channel:",
36-
this._instrumentsStepper,
36+
"Simultaneous instruments",
37+
br(),
38+
"per channel:",
39+
this._layeredInstrumentsBox,
40+
),
41+
div({style: "display: flex; flex-direction: row; align-items: center; height: 2em; justify-content: flex-end;"},
42+
"Different instruments",
43+
br(),
44+
"per pattern:",
45+
this._patternInstrumentsBox,
3746
),
3847
div({style: "display: flex; flex-direction: row-reverse; justify-content: space-between;"},
3948
this._okayButton,
@@ -46,10 +55,6 @@ export class ChannelSettingsPrompt implements Prompt {
4655
this._patternsStepper.min = "1";
4756
this._patternsStepper.max = Config.barCountMax + "";
4857

49-
this._instrumentsStepper.value = this._doc.song.instrumentsPerChannel + "";
50-
this._instrumentsStepper.min = Config.instrumentsPerChannelMin + "";
51-
this._instrumentsStepper.max = Config.instrumentsPerChannelMax + "";
52-
5358
this._pitchChannelStepper.value = this._doc.song.pitchChannelCount + "";
5459
this._pitchChannelStepper.min = Config.pitchChannelCountMin + "";
5560
this._pitchChannelStepper.max = Config.pitchChannelCountMax + "";
@@ -58,19 +63,20 @@ export class ChannelSettingsPrompt implements Prompt {
5863
this._drumChannelStepper.min = Config.noiseChannelCountMin + "";
5964
this._drumChannelStepper.max = Config.noiseChannelCountMax + "";
6065

66+
this._layeredInstrumentsBox.checked = this._doc.song.layeredInstruments;
67+
this._patternInstrumentsBox.checked = this._doc.song.patternInstruments;
68+
6169
this._pitchChannelStepper.select();
6270
setTimeout(()=>this._pitchChannelStepper.focus());
6371

6472
this._okayButton.addEventListener("click", this._saveChanges);
6573
this._cancelButton.addEventListener("click", this._close);
6674
this._patternsStepper.addEventListener("keypress", ChannelSettingsPrompt._validateKey);
67-
this._instrumentsStepper.addEventListener("keypress", ChannelSettingsPrompt._validateKey);
6875
this._pitchChannelStepper.addEventListener("keypress", ChannelSettingsPrompt._validateKey);
6976
this._drumChannelStepper.addEventListener("keypress", ChannelSettingsPrompt._validateKey);
70-
this._patternsStepper.addEventListener("blur", ChannelSettingsPrompt._validateNumber);
71-
this._instrumentsStepper.addEventListener("blur", ChannelSettingsPrompt._validateNumber);
72-
this._pitchChannelStepper.addEventListener("blur", ChannelSettingsPrompt._validateNumber);
73-
this._drumChannelStepper.addEventListener("blur", ChannelSettingsPrompt._validateNumber);
77+
this._patternsStepper.addEventListener("blur", this._validateNumber);
78+
this._pitchChannelStepper.addEventListener("blur", this._validateNumber);
79+
this._drumChannelStepper.addEventListener("blur", this._validateNumber);
7480
this.container.addEventListener("keydown", this._whenKeyPressed);
7581
}
7682

@@ -82,13 +88,11 @@ export class ChannelSettingsPrompt implements Prompt {
8288
this._okayButton.removeEventListener("click", this._saveChanges);
8389
this._cancelButton.removeEventListener("click", this._close);
8490
this._patternsStepper.removeEventListener("keypress", ChannelSettingsPrompt._validateKey);
85-
this._instrumentsStepper.removeEventListener("keypress", ChannelSettingsPrompt._validateKey);
8691
this._pitchChannelStepper.removeEventListener("keypress", ChannelSettingsPrompt._validateKey);
8792
this._drumChannelStepper.removeEventListener("keypress", ChannelSettingsPrompt._validateKey);
88-
this._patternsStepper.removeEventListener("blur", ChannelSettingsPrompt._validateNumber);
89-
this._instrumentsStepper.removeEventListener("blur", ChannelSettingsPrompt._validateNumber);
90-
this._pitchChannelStepper.removeEventListener("blur", ChannelSettingsPrompt._validateNumber);
91-
this._drumChannelStepper.removeEventListener("blur", ChannelSettingsPrompt._validateNumber);
93+
this._patternsStepper.removeEventListener("blur", this._validateNumber);
94+
this._pitchChannelStepper.removeEventListener("blur", this._validateNumber);
95+
this._drumChannelStepper.removeEventListener("blur", this._validateNumber);
9296
this.container.removeEventListener("keydown", this._whenKeyPressed);
9397
}
9498

@@ -107,7 +111,7 @@ export class ChannelSettingsPrompt implements Prompt {
107111
return false;
108112
}
109113

110-
private static _validateNumber(event: Event): void {
114+
private _validateNumber = (event: Event): void => {
111115
const input: HTMLInputElement = <HTMLInputElement>event.target;
112116
input.value = String(ChannelSettingsPrompt._validate(input));
113117
}
@@ -118,8 +122,8 @@ export class ChannelSettingsPrompt implements Prompt {
118122

119123
private _saveChanges = (): void => {
120124
const group: ChangeGroup = new ChangeGroup();
125+
group.append(new ChangeInstrumentsFlags(this._doc, this._layeredInstrumentsBox.checked, this._patternInstrumentsBox.checked));
121126
group.append(new ChangePatternsPerChannel(this._doc, ChannelSettingsPrompt._validate(this._patternsStepper)));
122-
group.append(new ChangeInstrumentsPerChannel(this._doc, ChannelSettingsPrompt._validate(this._instrumentsStepper)));
123127
group.append(new ChangeChannelCount(this._doc, ChannelSettingsPrompt._validate(this._pitchChannelStepper), ChannelSettingsPrompt._validate(this._drumChannelStepper)));
124128
this._doc.prompt = null;
125129
this._doc.record(group, true);

editor/ExportPrompt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ export class ExportPrompt implements Prompt {
526526

527527
if (pattern != null) {
528528

529-
const instrumentIndex: number = pattern.instrument;
529+
const instrumentIndex: number = pattern.instruments[0]; // Don't bother trying to export multiple instruments per pattern to midi, just pick the first one.
530530
const instrument: Instrument = song.channels[channel].instruments[instrumentIndex];
531531
const preset: Preset | null = EditorConfig.valueToPreset(instrument.preset);
532532
writeInstrumentSettings(instrumentIndex);

editor/ImportPrompt.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,8 @@ export class ImportPrompt implements Prompt {
448448
pattern = new Pattern();
449449
channel.patterns.push(pattern);
450450
channel.bars[currentBar] = channel.patterns.length;
451-
pattern.instrument = 0;
451+
pattern.instruments[0] = 0;
452+
pattern.instruments.length = 1;
452453
}
453454

454455
// Use the loudest volume setting for the instrument, since
@@ -588,7 +589,8 @@ export class ImportPrompt implements Prompt {
588589
channel.instruments.push(instrument);
589590
}
590591

591-
pattern.instrument = channel.instruments.indexOf(instrumentByProgram[currentProgram]);
592+
pattern.instruments[0] = channel.instruments.indexOf(instrumentByProgram[currentProgram]);
593+
pattern.instruments.length = 1;
592594
}
593595

594596
// Use the loudest volume setting for the instrument, since
@@ -818,7 +820,7 @@ export class ImportPrompt implements Prompt {
818820
channelA.instruments.push(instrument);
819821
}
820822
for (const pattern of channelB.patterns) {
821-
pattern.instrument += channelAInstrumentCount;
823+
pattern.instruments[0] += channelAInstrumentCount;
822824
channelA.patterns.push(pattern);
823825
}
824826
for (let barIndex: number = 0; barIndex < channelA.bars.length && barIndex < channelB.bars.length; barIndex++) {
@@ -844,6 +846,8 @@ export class ImportPrompt implements Prompt {
844846
song.key = key;
845847
song.scale = 11;
846848
song.rhythm = 1;
849+
song.layeredInstruments = false;
850+
song.patternInstruments = pitchChannels.some(channel => channel.instruments.length > 1) || noiseChannels.some(channel => channel.instruments.length > 1);
847851

848852
removeDuplicatePatterns(pitchChannels);
849853
removeDuplicatePatterns(noiseChannels);

editor/Piano.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export class Piano {
182182
this._updateCursorPitch();
183183
if (this._mouseDown) this._playLiveInput();
184184
this._doc.synth.liveInputChannel = this._doc.channel;
185+
this._doc.synth.liveInputInstruments = this._doc.recentPatternInstruments[this._doc.channel];
185186

186187
if (!this._doc.showLetters) return;
187188
if (this._renderedScale == this._doc.song.scale && this._renderedKey == this._doc.song.key && this._renderedDrums == isDrum && this._renderedPitchCount == this._pitchCount) return;

0 commit comments

Comments
 (0)