feat: added autobeat for full bars
This commit is contained in:
86
src/Beat.ts
86
src/Beat.ts
@@ -1,4 +1,4 @@
|
|||||||
import BeatUnit, {BeatUnitType} from "./BeatUnit";
|
import BeatUnit from "./BeatUnit";
|
||||||
import {IPublisher, Publisher} from "./Publisher";
|
import {IPublisher, Publisher} from "./Publisher";
|
||||||
import ISubscriber from "./Subscriber";
|
import ISubscriber from "./Subscriber";
|
||||||
import BeatLike from "./BeatLike";
|
import BeatLike from "./BeatLike";
|
||||||
@@ -15,13 +15,12 @@ export type BeatInitOptions = {
|
|||||||
loopLength?: number,
|
loopLength?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum BeatEvents {
|
export const enum BeatEvents {
|
||||||
NewTimeSig,
|
NewTimeSig="BE0",
|
||||||
NewBarCount,
|
NewBarCount="BE1",
|
||||||
NewName,
|
NewName="BE2",
|
||||||
UnitChanged,
|
DisplayTypeChanged="BE3",
|
||||||
DisplayTypeChanged,
|
LoopLengthChanged="BE4",
|
||||||
LoopLengthChanged,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
||||||
@@ -48,9 +47,9 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
|
|
||||||
setLoopLength(loopLength: number): void {
|
setLoopLength(loopLength: number): void {
|
||||||
if (!isPosInt(loopLength) || loopLength < 2) {
|
if (!isPosInt(loopLength) || loopLength < 2) {
|
||||||
return;
|
loopLength = this.loopLength;
|
||||||
}
|
}
|
||||||
this.loopLength = loopLength | 0;
|
this.loopLength = loopLength;
|
||||||
this.publisher.notifySubs(BeatEvents.LoopLengthChanged);
|
this.publisher.notifySubs(BeatEvents.LoopLengthChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,14 +58,13 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
this.publisher.notifySubs(BeatEvents.DisplayTypeChanged);
|
this.publisher.notifySubs(BeatEvents.DisplayTypeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: BeatEvents | "all"): { unbind: () => void } {
|
addSubscriber(subscriber: ISubscriber, eventType: BeatEvents | BeatEvents[] | "all"): { unbind: () => void } {
|
||||||
return this.publisher.addSubscriber(subscriber, eventType);
|
return this.publisher.addSubscriber(subscriber, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeSignature(timeSig: {up?: number, down?: number}): void {
|
setTimeSignature(timeSig: {up?: number, down?: number}): void {
|
||||||
if (timeSig.up && Beat.isValidTimeSigRange(timeSig.up)) {
|
if (timeSig.up && Beat.isValidTimeSigRange(timeSig.up)) {
|
||||||
this.timeSigUp = timeSig.up | 0;
|
this.timeSigUp = timeSig.up | 0;
|
||||||
this.loopLength = this.timeSigUp * this.barCount;
|
|
||||||
}
|
}
|
||||||
if (timeSig.down && Beat.isValidTimeSigRange(timeSig.down)) {
|
if (timeSig.down && Beat.isValidTimeSigRange(timeSig.down)) {
|
||||||
this.timeSigDown = timeSig.down | 0;
|
this.timeSigDown = timeSig.down | 0;
|
||||||
@@ -77,17 +75,16 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
|
|
||||||
setBarCount(barCount: number): void {
|
setBarCount(barCount: number): void {
|
||||||
if (!isPosInt(barCount) || barCount == this.barCount) {
|
if (!isPosInt(barCount) || barCount == this.barCount) {
|
||||||
return;
|
barCount = this.barCount;
|
||||||
}
|
}
|
||||||
this.barCount = barCount;
|
this.barCount = barCount;
|
||||||
this.loopLength = this.timeSigUp * this.barCount;
|
|
||||||
this.updateBeatUnitLength();
|
this.updateBeatUnitLength();
|
||||||
this.publisher.notifySubs(BeatEvents.NewBarCount);
|
this.publisher.notifySubs(BeatEvents.NewBarCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUnitByIndex(index: number): BeatUnit | null {
|
getUnitByIndex(index: number): BeatUnit | null {
|
||||||
if (this.looping) {
|
if (this.looping) {
|
||||||
return this.unitRecord[index % this.loopLength];
|
index %= this.loopLength;
|
||||||
}
|
}
|
||||||
return this.unitRecord[index] ?? null;
|
return this.unitRecord[index] ?? null;
|
||||||
}
|
}
|
||||||
@@ -112,63 +109,6 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
return this.timeSigDown;
|
return this.timeSigDown;
|
||||||
}
|
}
|
||||||
|
|
||||||
turnUnitOn(index: number): void {
|
|
||||||
if (!isPosInt(index)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const unit = this.getUnit(index);
|
|
||||||
if (unit) {
|
|
||||||
unit.setOn(true);
|
|
||||||
this.publisher.notifySubs(BeatEvents.UnitChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
turnUnitOff(index: number): void {
|
|
||||||
if (!isPosInt(index)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const unit = this.getUnit(index);
|
|
||||||
if (unit) {
|
|
||||||
unit.setOn(false);
|
|
||||||
this.publisher.notifySubs(BeatEvents.UnitChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toggleUnit(index: number): void {
|
|
||||||
if (!isPosInt(index)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const unit = this.getUnit(index);
|
|
||||||
if (unit) {
|
|
||||||
unit.toggle();
|
|
||||||
this.publisher.notifySubs(BeatEvents.UnitChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setUnitType(index: number, type: BeatUnitType): void {
|
|
||||||
if (!isPosInt(index)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.getUnit(index).setType(type);
|
|
||||||
this.publisher.notifySubs(BeatEvents.UnitChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
unitIsOn(index: number): boolean {
|
|
||||||
return this.getUnit(index)?.isOn();
|
|
||||||
}
|
|
||||||
|
|
||||||
unitType(index: number): BeatUnitType {
|
|
||||||
return this.getUnit(index)?.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getUnit(index: number): BeatUnit {
|
|
||||||
if (!this.unitRecord[index]) {
|
|
||||||
throw new Error(`Invalid beat unit index! - ${index}`);
|
|
||||||
}
|
|
||||||
return this.unitRecord[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
getBarCount(): number {
|
getBarCount(): number {
|
||||||
return this.barCount;
|
return this.barCount;
|
||||||
}
|
}
|
||||||
@@ -178,7 +118,7 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static isValidTimeSigRange(sig: number): boolean {
|
static isValidTimeSigRange(sig: number): boolean {
|
||||||
return sig >= 2 && sig <= 64;
|
return sig >= 2 && sig <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
setName(newName: string): void {
|
setName(newName: string): void {
|
||||||
|
|||||||
107
src/BeatGroup.ts
107
src/BeatGroup.ts
@@ -10,23 +10,28 @@ type BeatGroupInitOptions = {
|
|||||||
timeSigUp: number;
|
timeSigUp: number;
|
||||||
beats: BeatInitOptions[],
|
beats: BeatInitOptions[],
|
||||||
loopLength?: number,
|
loopLength?: number,
|
||||||
|
forceFullBars?: boolean,
|
||||||
|
useAutoBeatLength?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum BeatGroupEvents {
|
export const enum BeatGroupEvents {
|
||||||
BeatOrderChanged,
|
BeatOrderChanged="BGE0",
|
||||||
BeatListChanged,
|
BeatListChanged="BGE1",
|
||||||
GlobalBarCountChanged,
|
BarCountChanged="BGE2",
|
||||||
GlobalTimeSigUpChanged,
|
TimeSigUpChanged="BGE3",
|
||||||
|
AutoBeatSettingsChanged="BGE4",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvents>, BeatLike {
|
export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvents>, BeatLike, ISubscriber {
|
||||||
private beats: Beat[] = [];
|
private beats: Beat[] = [];
|
||||||
private beatKeyMap: Record<string, number> = {};
|
private beatKeyMap: Record<string, number> = {};
|
||||||
private publisher: Publisher<BeatGroupEvents | BeatEvents> = new Publisher<BeatGroupEvents | BeatEvents>();
|
private publisher: Publisher<BeatGroupEvents | BeatEvents> = new Publisher<BeatGroupEvents | BeatEvents>();
|
||||||
private globalBarCount: number;
|
private barCount: number;
|
||||||
private globalTimeSigUp: number;
|
private timeSigUp: number;
|
||||||
private globalLoopLength: number;
|
private globalLoopLength: number;
|
||||||
private globalIsLooping: boolean;
|
private globalIsLooping: boolean;
|
||||||
|
private forceFullBars: boolean;
|
||||||
|
private useAutoBeatLength: boolean;
|
||||||
|
|
||||||
constructor(options?: BeatGroupInitOptions) {
|
constructor(options?: BeatGroupInitOptions) {
|
||||||
if (options?.beats) {
|
if (options?.beats) {
|
||||||
@@ -36,10 +41,18 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
this.beatKeyMap[newBeat.getKey()] = this.beats.length - 1;
|
this.beatKeyMap[newBeat.getKey()] = this.beats.length - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.globalBarCount = options?.barCount ?? 4;
|
this.barCount = options?.barCount ?? 4;
|
||||||
this.globalTimeSigUp = options?.timeSigUp ?? 4;
|
this.timeSigUp = options?.timeSigUp ?? 4;
|
||||||
this.globalLoopLength = options?.loopLength ?? this.globalBarCount * this.globalTimeSigUp;
|
this.globalLoopLength = options?.loopLength ?? this.barCount * this.timeSigUp;
|
||||||
this.globalIsLooping = options?.isLooping ?? false;
|
this.globalIsLooping = options?.isLooping ?? false;
|
||||||
|
this.useAutoBeatLength = options?.useAutoBeatLength ?? false;
|
||||||
|
this.forceFullBars = options?.forceFullBars ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
||||||
|
if (event === BeatEvents.LoopLengthChanged) {
|
||||||
|
this.autoBeatLength();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatGroupEvents | BeatEvents | (BeatGroupEvents | BeatEvents)[]): { unbind: () => void } {
|
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatGroupEvents | BeatEvents | (BeatGroupEvents | BeatEvents)[]): { unbind: () => void } {
|
||||||
@@ -47,18 +60,18 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
setBarCount(barCount: number): void {
|
setBarCount(barCount: number): void {
|
||||||
if (barCount <= 0 || (barCount | 0) !== barCount) {
|
if (!isPosInt(barCount)) {
|
||||||
return;
|
barCount = this.barCount;
|
||||||
}
|
}
|
||||||
this.globalBarCount = barCount;
|
this.barCount = barCount;
|
||||||
for (const beat of this.beats) {
|
for (const beat of this.beats) {
|
||||||
beat.setBarCount(barCount);
|
beat.setBarCount(barCount);
|
||||||
}
|
}
|
||||||
this.publisher.notifySubs(BeatGroupEvents.GlobalBarCountChanged);
|
this.publisher.notifySubs(BeatGroupEvents.BarCountChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBarCount(): number {
|
getBarCount(): number {
|
||||||
return this.globalBarCount;
|
return this.barCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoopLength(loopLength: number): void {
|
setLoopLength(loopLength: number): void {
|
||||||
@@ -81,6 +94,9 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
for (const beat of this.beats) {
|
for (const beat of this.beats) {
|
||||||
beat.setLooping(isLooping);
|
beat.setLooping(isLooping);
|
||||||
}
|
}
|
||||||
|
if (isLooping) {
|
||||||
|
this.autoBeatLength();
|
||||||
|
}
|
||||||
this.publisher.notifySubs(BeatEvents.DisplayTypeChanged);
|
this.publisher.notifySubs(BeatEvents.DisplayTypeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +104,39 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
return this.globalIsLooping;
|
return this.globalIsLooping;
|
||||||
}
|
}
|
||||||
|
|
||||||
setGlobalTimeSigUp(timeSigUp: number): void {
|
private findSmallestLoopLength(): number {
|
||||||
if (!Beat.isValidTimeSigRange(timeSigUp)) {
|
const loopLengths = [];
|
||||||
return;
|
const denominators = [];
|
||||||
|
for (const beat of this.beats) {
|
||||||
|
loopLengths.push(beat.getLoopLength());
|
||||||
}
|
}
|
||||||
this.globalTimeSigUp = timeSigUp;
|
if (this.forceFullBars) {
|
||||||
|
loopLengths.push(this.timeSigUp);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < loopLengths.length; i++) {
|
||||||
|
let isFactor = false;
|
||||||
|
for (let j = 0; j < loopLengths.length; j++) {
|
||||||
|
if (j !== i && loopLengths[j] % loopLengths[i] === 0 && loopLengths[j] !== loopLengths[i]) {
|
||||||
|
isFactor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isFactor && denominators.indexOf(loopLengths[i]) === -1) {
|
||||||
|
denominators.push(loopLengths[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return denominators.reduce((prev, curr) => prev * curr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeSigUp(timeSigUp: number): void {
|
||||||
|
if (!Beat.isValidTimeSigRange(timeSigUp)) {
|
||||||
|
timeSigUp = this.timeSigUp;
|
||||||
|
}
|
||||||
|
this.timeSigUp = timeSigUp;
|
||||||
for (const beat of this.beats) {
|
for (const beat of this.beats) {
|
||||||
beat.setTimeSignature({up: timeSigUp});
|
beat.setTimeSignature({up: timeSigUp});
|
||||||
}
|
}
|
||||||
this.publisher.notifySubs(BeatGroupEvents.GlobalTimeSigUpChanged);
|
this.publisher.notifySubs(BeatGroupEvents.TimeSigUpChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBeatByKey(beatKey: string): Beat {
|
getBeatByKey(beatKey: string): Beat {
|
||||||
@@ -165,6 +205,7 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
const newBeat = new Beat(options);
|
const newBeat = new Beat(options);
|
||||||
this.beats.push(newBeat);
|
this.beats.push(newBeat);
|
||||||
this.beatKeyMap[newBeat.getKey()] = this.beats.length;
|
this.beatKeyMap[newBeat.getKey()] = this.beats.length;
|
||||||
|
newBeat.addSubscriber(this, [BeatEvents.LoopLengthChanged]);
|
||||||
this.publisher.notifySubs(BeatGroupEvents.BeatListChanged);
|
this.publisher.notifySubs(BeatGroupEvents.BeatListChanged);
|
||||||
return newBeat;
|
return newBeat;
|
||||||
}
|
}
|
||||||
@@ -179,4 +220,30 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
this.getBeatByKey(beatKey).setName(newName);
|
this.getBeatByKey(beatKey).setName(newName);
|
||||||
this.publisher.notifySubs(BeatGroupEvents.BeatOrderChanged);
|
this.publisher.notifySubs(BeatGroupEvents.BeatOrderChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autoBeatLengthOn(): boolean {
|
||||||
|
return this.useAutoBeatLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
forcesFullBars(): boolean {
|
||||||
|
return this.forceFullBars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private autoBeatLength(): void {
|
||||||
|
if (this.useAutoBeatLength && this.globalIsLooping) {
|
||||||
|
this.setBarCount(this.findSmallestLoopLength() / this.timeSigUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsUsingAutoBeatLength(isOn: boolean): void {
|
||||||
|
this.useAutoBeatLength = isOn;
|
||||||
|
this.autoBeatLength();
|
||||||
|
this.publisher.notifySubs(BeatGroupEvents.AutoBeatSettingsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
setForcesFullBars(force: boolean): void {
|
||||||
|
this.forceFullBars = force;
|
||||||
|
this.autoBeatLength();
|
||||||
|
this.publisher.notifySubs(BeatGroupEvents.AutoBeatSettingsChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import Beat, {BeatEvents} from "../../../../Beat";
|
|||||||
import {IPublisher} from "../../../../Publisher";
|
import {IPublisher} from "../../../../Publisher";
|
||||||
import ISubscriber from "../../../../Subscriber";
|
import ISubscriber from "../../../../Subscriber";
|
||||||
import "./BeatSettings.css";
|
import "./BeatSettings.css";
|
||||||
import BeatLike from "../../../../BeatLike";
|
|
||||||
import BeatLikeLoopSettingsView from "../../BeatLikeLoopSettings/BeatLikeLoopSettingsView";
|
import BeatLikeLoopSettingsView from "../../BeatLikeLoopSettings/BeatLikeLoopSettingsView";
|
||||||
|
|
||||||
export type BeatSettingsViewUINodeOptions = UINodeOptions & {
|
export type BeatSettingsViewUINodeOptions = UINodeOptions & {
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
private beatUnitViews: BeatUnitView[] = [];
|
private beatUnitViews: BeatUnitView[] = [];
|
||||||
private beatUnitViewBlock: HTMLElement | null = null;
|
private beatUnitViewBlock: HTMLElement | null = null;
|
||||||
private lastHoveredBeatUnitView: BeatUnitView | null = null;
|
private lastHoveredBeatUnitView: BeatUnitView | null = null;
|
||||||
private static deselectingUnits = false;
|
static deselectingUnits = false;
|
||||||
private static selectingUnits = false;
|
static selectingUnits = false;
|
||||||
|
|
||||||
constructor(options: BeatUINodeOptions) {
|
constructor(options: BeatUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -68,11 +68,6 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
view = new BeatUnitView({beatUnit});
|
view = new BeatUnitView({beatUnit});
|
||||||
this.beatUnitViews.push(view);
|
this.beatUnitViews.push(view);
|
||||||
}
|
}
|
||||||
view.onMouseDown((event: MouseEvent) => this.onBeatUnitClick(event.button, i));
|
|
||||||
window.addEventListener("mouseup", (event: MouseEvent) => {
|
|
||||||
BeatView.selectingUnits = false;
|
|
||||||
BeatView.deselectingUnits = false;
|
|
||||||
});
|
|
||||||
view.onHover(() => {
|
view.onHover(() => {
|
||||||
this.lastHoveredBeatUnitView = view;
|
this.lastHoveredBeatUnitView = view;
|
||||||
if (BeatView.selectingUnits) {
|
if (BeatView.selectingUnits) {
|
||||||
@@ -81,6 +76,7 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
this.lastHoveredBeatUnitView.turnOff();
|
this.lastHoveredBeatUnitView.turnOff();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
view.onMouseDown((event: MouseEvent) => this.onBeatUnitClick(event.button, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,6 +145,9 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
classes: ["beat-title"],
|
classes: ["beat-title"],
|
||||||
});
|
});
|
||||||
this.setupBeatUnits();
|
this.setupBeatUnits();
|
||||||
|
if (!this.beatUnitViewBlock) {
|
||||||
|
throw new Error("Beat unit block setup failed!");
|
||||||
|
}
|
||||||
this.settingsView = new BeatSettingsView({beat: this.beat});
|
this.settingsView = new BeatSettingsView({beat: this.beat});
|
||||||
this.settingsToggleButton = UINode.make("div", {
|
this.settingsToggleButton = UINode.make("div", {
|
||||||
classes: ["beat-settings-btn"],
|
classes: ["beat-settings-btn"],
|
||||||
@@ -162,7 +161,7 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
classes: ["beat-main"],
|
classes: ["beat-main"],
|
||||||
subs: [
|
subs: [
|
||||||
this.title,
|
this.title,
|
||||||
this.beatUnitViewBlock!,
|
this.beatUnitViewBlock,
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
this.settingsToggleButton,
|
this.settingsToggleButton,
|
||||||
@@ -175,3 +174,8 @@ export default class BeatView extends UINode implements ISubscriber {
|
|||||||
return this.node;
|
return this.node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("mouseup", () => {
|
||||||
|
BeatView.selectingUnits = false;
|
||||||
|
BeatView.deselectingUnits = false;
|
||||||
|
});
|
||||||
@@ -12,3 +12,10 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.beat-group-settings-option-group {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.beat-group-settings-option-group.visible {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {IPublisher} from "../../../Publisher";
|
|||||||
import {BeatGroupEvents} from "../../../BeatGroup";
|
import {BeatGroupEvents} from "../../../BeatGroup";
|
||||||
import BeatLikeLoopSettingsView from "../BeatLikeLoopSettings/BeatLikeLoopSettingsView";
|
import BeatLikeLoopSettingsView from "../BeatLikeLoopSettings/BeatLikeLoopSettingsView";
|
||||||
import "./BeatGroupSettings.css";
|
import "./BeatGroupSettings.css";
|
||||||
|
import {BeatEvents} from "../../../Beat";
|
||||||
|
|
||||||
export type BeatGroupSettingsUINodeOptions = UINodeOptions & {
|
export type BeatGroupSettingsUINodeOptions = UINodeOptions & {
|
||||||
beatGroup: BeatGroup,
|
beatGroup: BeatGroup,
|
||||||
@@ -15,21 +16,31 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
|
|||||||
private barCountInput!: HTMLInputElement;
|
private barCountInput!: HTMLInputElement;
|
||||||
private timeSigUpInput!: HTMLInputElement;
|
private timeSigUpInput!: HTMLInputElement;
|
||||||
private loopSettingsView!: BeatLikeLoopSettingsView;
|
private loopSettingsView!: BeatLikeLoopSettingsView;
|
||||||
|
private autoBeatLengthCheckbox!: HTMLInputElement;
|
||||||
|
private forceFullBarsCheckbox!: HTMLInputElement;
|
||||||
|
private autoBeatOptions!: HTMLElement;
|
||||||
|
|
||||||
constructor(options: BeatGroupSettingsUINodeOptions) {
|
constructor(options: BeatGroupSettingsUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
this.beatGroup = options.beatGroup;
|
this.beatGroup = options.beatGroup;
|
||||||
this.beatGroup.addSubscriber(this, [
|
this.beatGroup.addSubscriber(this, [
|
||||||
BeatGroupEvents.GlobalBarCountChanged,
|
BeatGroupEvents.BarCountChanged,
|
||||||
BeatGroupEvents.GlobalTimeSigUpChanged
|
BeatGroupEvents.TimeSigUpChanged,
|
||||||
|
BeatEvents.DisplayTypeChanged,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
||||||
if (event === BeatGroupEvents.GlobalBarCountChanged) {
|
if (event === BeatGroupEvents.BarCountChanged) {
|
||||||
this.barCountInput.value = this.beatGroup.getBeatByIndex(0).getBarCount().toString();
|
this.barCountInput.valueAsNumber = this.beatGroup.getBeatByIndex(0).getBarCount();
|
||||||
} else if (event === BeatGroupEvents.GlobalTimeSigUpChanged) {
|
} else if (event === BeatGroupEvents.TimeSigUpChanged) {
|
||||||
this.barCountInput.value = this.beatGroup.getBeatByIndex(0).getBarCount().toString();
|
this.timeSigUpInput.valueAsNumber = this.beatGroup.getBeatByIndex(0).getTimeSigUp();
|
||||||
|
} else if (event === BeatEvents.DisplayTypeChanged) {
|
||||||
|
if (this.beatGroup.isLooping()) {
|
||||||
|
this.autoBeatOptions.classList.add("visible");
|
||||||
|
} else {
|
||||||
|
this.autoBeatOptions.classList.remove("visible");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,13 +57,44 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
|
|||||||
type: "number",
|
type: "number",
|
||||||
value: this.beatGroup.getBeatByIndex(0).getTimeSigUp().toString(),
|
value: this.beatGroup.getBeatByIndex(0).getTimeSigUp().toString(),
|
||||||
oninput: () => {
|
oninput: () => {
|
||||||
this.beatGroup.setGlobalTimeSigUp(Number(this.timeSigUpInput.value));
|
this.beatGroup.setTimeSigUp(Number(this.timeSigUpInput.value));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.autoBeatLengthCheckbox = UINode.make("input", {
|
||||||
|
type: "checkbox",
|
||||||
|
checked: this.beatGroup.autoBeatLengthOn(),
|
||||||
|
oninput: () => {
|
||||||
|
this.beatGroup.setIsUsingAutoBeatLength(this.autoBeatLengthCheckbox.checked);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.forceFullBarsCheckbox = UINode.make("input", {
|
||||||
|
type: "checkbox",
|
||||||
|
checked: this.beatGroup.forcesFullBars(),
|
||||||
|
oninput: () => {
|
||||||
|
this.beatGroup.setForcesFullBars(this.forceFullBarsCheckbox.checked);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.autoBeatOptions = UINode.make("div", {
|
||||||
|
classes: ["beat-group-settings-option-group"],
|
||||||
|
subs: [
|
||||||
|
UINode.make("div", {
|
||||||
|
subs: [
|
||||||
|
UINode.make("label", { innerText: "Auto beat length:"}),
|
||||||
|
this.autoBeatLengthCheckbox,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
UINode.make("div", {
|
||||||
|
subs: [
|
||||||
|
UINode.make("label", { innerText: "Force full bars:"}),
|
||||||
|
this.forceFullBarsCheckbox,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
});
|
||||||
this.node = UINode.make("div", {
|
this.node = UINode.make("div", {
|
||||||
classes: ["beat-group-settings"],
|
classes: ["beat-group-settings"],
|
||||||
subs: [
|
subs: [
|
||||||
UINode.make("h4", { innerText: "Settings for beat" }),
|
UINode.make("div", { innerText: "Settings for beat" }),
|
||||||
UINode.make("div", {
|
UINode.make("div", {
|
||||||
classes: ["beat-group-settings-options"],
|
classes: ["beat-group-settings-options"],
|
||||||
subs: [
|
subs: [
|
||||||
@@ -71,6 +113,7 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
this.loopSettingsView.render(),
|
this.loopSettingsView.render(),
|
||||||
|
this.autoBeatOptions,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ export default class BeatLikeLoopSettingsView extends UINode implements ISubscri
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupBindings() {
|
private setupBindings() {
|
||||||
this.beatLike.addSubscriber(this, "all");
|
this.beatLike.addSubscriber(this, [
|
||||||
|
BeatEvents.LoopLengthChanged,
|
||||||
|
BeatEvents.DisplayTypeChanged
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user