ControlPanel.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import { AUIController } from "../../../MusicalScore/Interfaces/AUIController";
  2. import rawHtml from "./ControlPanel.html";
  3. import rawVolumeItemHtml from "./VolumeItem.html";
  4. import rawPlaybackButtonHtml from "./PlaybackButtons.html";
  5. import {MDCSlider} from "@material/slider";
  6. import { IPlaybackParametersListener } from "../../../Common/Interfaces/IPlaybackParametersListener";
  7. import { PlayPauseButton } from "./PlayPauseButton";
  8. import { MDCTabBar } from "@material/tab-bar";
  9. import {MDCRipple} from "@material/ripple";
  10. import {MDCIconButtonToggle} from "@material/icon-button";
  11. import { Dictionary } from "typescript-collections";
  12. export class ControlPanel extends AUIController<IPlaybackParametersListener> implements IPlaybackParametersListener {
  13. //TODO: We need this to be updated if the score changes these parameters as well
  14. public volumeMute(instrument: number): void {
  15. throw new Error("Method not implemented.");
  16. }
  17. public volumeUnmute(instrument: number): void {
  18. throw new Error("Method not implemented.");
  19. }
  20. public bpmChanged(newNpm: number): void {
  21. this.bpmValue = newNpm;
  22. if (this.bpmSlider) {
  23. this.bpmSlider.value = this.bpmValue;
  24. }
  25. }
  26. public volumeChanged(channels: number, newVolume: number): void {
  27. throw new Error("Method not implemented.");
  28. }
  29. public play(): Promise<void> {
  30. throw new Error("Method not implemented.");
  31. }
  32. public pause(): Promise<void> {
  33. throw new Error("Method not implemented.");
  34. }
  35. public reset(): void {
  36. throw new Error("Method not implemented.");
  37. }
  38. private controlPanelElement: HTMLDivElement;
  39. private playbackButtonsContainerElement: HTMLDivElement;
  40. private metronomeToolbarElement: HTMLDivElement;
  41. private volumeToolbarElement: HTMLDivElement;
  42. private bpmValue: number = 80;
  43. private bpmSlider: MDCSlider;
  44. private volumeSliders: Dictionary<number, MDCSlider> = new Dictionary<number, MDCSlider>();
  45. private volumeSliderElements: Dictionary<number, HTMLDivElement> = new Dictionary<number, HTMLDivElement>();
  46. private playPauseButton: PlayPauseButton;
  47. private resetButton: HTMLButtonElement;
  48. private titleContentElement: HTMLHeadingElement;
  49. private closeButtonElement: HTMLButtonElement;
  50. public get IsClosed(): boolean {
  51. return this.controlPanelElement.classList.contains("hide");
  52. }
  53. public clearVolumeTracks(): void {
  54. for (const slider of this.volumeSliders.values()) {
  55. slider.destroy();
  56. }
  57. this.volumeSliders.clear();
  58. for (const element of this.volumeSliderElements.values()) {
  59. element.parentElement.remove();
  60. }
  61. this.volumeSliderElements.clear();
  62. }
  63. public addVolumeTrack(name: string, id: number, value: number = 80): void {
  64. const newVolumeItem: string = this.generateHtmlTemplate(rawVolumeItemHtml, {name: name, id: id.toString()});
  65. this.volumeToolbarElement.insertAdjacentHTML("beforeend", newVolumeItem);
  66. const volSliderParentElement: HTMLDivElement = this.volumeToolbarElement.lastChild as HTMLDivElement;
  67. const volSliderElement: HTMLDivElement = volSliderParentElement.getElementsByClassName("volume-slider")[0] as HTMLDivElement;
  68. const volMuteButtonElement: HTMLButtonElement = volSliderParentElement.getElementsByClassName("mute-button")[0] as HTMLButtonElement;
  69. const iconToggle: MDCIconButtonToggle = new MDCIconButtonToggle(volMuteButtonElement);
  70. iconToggle.initialize();
  71. this.volumeSliderElements.setValue(id, volSliderElement);
  72. const volumeSlider: MDCSlider = new MDCSlider(volSliderElement);
  73. volumeSlider.value = value;
  74. volumeSlider.initialize();
  75. const self: ControlPanel = this;
  76. iconToggle.listen("MDCIconButtonToggle:change", function(event: CustomEvent): void {
  77. event.preventDefault();
  78. for (const listener of self.eventListeners) {
  79. if (event.detail.isOn) {
  80. listener.volumeMute(id);
  81. } else {
  82. listener.volumeUnmute(id);
  83. volMuteButtonElement.classList.remove("mdc-ripple-upgraded--background-focused");
  84. }
  85. }
  86. });
  87. iconToggle.on = false;
  88. volumeSlider.listen("MDCSlider:input", () => {
  89. for (const listener of self.eventListeners) {
  90. listener.volumeChanged(id, volumeSlider.value);
  91. }
  92. });
  93. this.volumeSliders.setValue(id, volumeSlider);
  94. }
  95. protected initialize(): void {
  96. this.generateAndInsertHtmlTemplate(rawHtml);
  97. this.controlPanelElement = this.parentElement.lastChild as HTMLDivElement;
  98. this.generateAndInsertHtmlTemplate(rawPlaybackButtonHtml);
  99. this.playbackButtonsContainerElement = this.parentElement.lastChild as HTMLDivElement;
  100. this.resetButton = this.playbackButtonsContainerElement.getElementsByClassName("reset-button")[0] as HTMLButtonElement;
  101. this.playPauseButton = new PlayPauseButton(this.playbackButtonsContainerElement.getElementsByClassName("playpause-button")[0] as HTMLButtonElement);
  102. this.playPauseButton.listen((state) => {
  103. if (state === "playing") {
  104. for (const listener of self.eventListeners) {
  105. listener.play();
  106. }
  107. } else {
  108. for (const listener of self.eventListeners) {
  109. listener.pause();
  110. }
  111. }
  112. });
  113. this.resetButton.addEventListener("click", () => {
  114. for (const listener of self.eventListeners) {
  115. listener.reset();
  116. }
  117. });
  118. document.addEventListener("keydown", (event: KeyboardEvent) => {
  119. if (event.code === "ArrowLeft") {
  120. for (const listener of self.eventListeners) {
  121. listener.reset();
  122. }
  123. }
  124. });
  125. this.metronomeToolbarElement = document.getElementById("metronome-toolbar") as HTMLDivElement;
  126. this.volumeToolbarElement = document.getElementById("volume-toolbar") as HTMLDivElement;
  127. const tabBar: MDCTabBar = new MDCTabBar(document.getElementById("playback-tabs"));
  128. tabBar.initialize();
  129. this.titleContentElement = document.getElementById("playback-title") as HTMLHeadingElement;
  130. this.closeButtonElement = document.getElementById("close-playback") as HTMLButtonElement;
  131. const buttonRipple: MDCRipple = new MDCRipple(this.closeButtonElement);
  132. buttonRipple.unbounded = true;
  133. buttonRipple.initialize();
  134. const self: ControlPanel = this;
  135. this.closeButtonElement[this.upEventName] = function(): void {
  136. self.hideAndClear();
  137. //self.eventListener.onClose();
  138. };
  139. tabBar.listen("MDCTabBar:activated", function(event: CustomEvent): void {
  140. switch (event.detail.index) {
  141. case 0:
  142. self.metronomeToolbarElement.classList.remove("hide");
  143. self.volumeToolbarElement.classList.add("hide");
  144. self.bpmSlider?.destroy();
  145. self.bpmSlider = new MDCSlider(self.controlPanelElement.getElementsByClassName("metronome-slider")[0]);
  146. self.bpmSlider.initialize();
  147. self.bpmSlider.value = self.bpmValue;
  148. self.bpmSlider.listen("MDCSlider:input", () => {
  149. self.bpmValue = self.bpmSlider.value;
  150. for (const listener of self.eventListeners) {
  151. listener.bpmChanged(self.bpmValue);
  152. }
  153. });
  154. self.titleContentElement.innerText = "Tempo (BPM)";
  155. break;
  156. case 1:
  157. self.metronomeToolbarElement.classList.add("hide");
  158. self.volumeToolbarElement.classList.remove("hide");
  159. for (const midiIds of self.volumeSliders.keys()) {
  160. let slider: MDCSlider = self.volumeSliders.getValue(midiIds);
  161. slider.destroy();
  162. slider = new MDCSlider(self.volumeSliderElements.getValue(midiIds));
  163. slider.initialize();
  164. slider.listen("MDCSlider:input", () => {
  165. for (const listener of self.eventListeners) {
  166. listener.volumeChanged(midiIds, slider.value);
  167. }
  168. });
  169. }
  170. self.titleContentElement.innerText = "Volume Mixer";
  171. break;
  172. default:
  173. break;
  174. }
  175. });
  176. }
  177. public hideAndClear(): void {
  178. this.controlPanelElement.classList.add("hide");
  179. }
  180. public show(): void {
  181. this.controlPanelElement.classList.remove("hide");
  182. const self: ControlPanel = this;
  183. if (this.metronomeToolbarElement.classList.contains("hide")) {
  184. for (const midiIds of self.volumeSliders.keys()) {
  185. let slider: MDCSlider = self.volumeSliders.getValue(midiIds);
  186. slider.destroy();
  187. slider = new MDCSlider(self.volumeSliderElements.getValue(midiIds));
  188. slider.initialize();
  189. slider.listen("MDCSlider:input", () => {
  190. for (const listener of self.eventListeners) {
  191. listener.volumeChanged(midiIds, slider.value);
  192. }
  193. });
  194. }
  195. } else {
  196. this.bpmSlider?.destroy();
  197. this.bpmSlider = new MDCSlider(this.controlPanelElement.getElementsByClassName("metronome-slider")[0]);
  198. this.bpmSlider.initialize();
  199. this.bpmSlider.value = this.bpmValue;
  200. this.bpmSlider.listen("MDCSlider:input", () => {
  201. this.bpmValue = self.bpmSlider.value;
  202. for (const listener of self.eventListeners) {
  203. listener.bpmChanged(self.bpmSlider.value);
  204. }
  205. });
  206. }
  207. }
  208. }