diff --git a/src/client/components/mod-player.vue b/src/client/components/mod-player.vue index a568e3c56..ad84538e2 100644 --- a/src/client/components/mod-player.vue +++ b/src/client/components/mod-player.vue @@ -10,13 +10,18 @@
- + + + +
@@ -37,6 +42,7 @@ export default defineComponent({ data() { return { hide: true, + playing: false }; }, created() { @@ -46,6 +52,9 @@ export default defineComponent({ this.buffer = null; this.player.load(this.module.url).then((result) => { this.buffer = result; + this.player.play(this.buffer); + this.display(); + this.player.stop(); }).catch((error) => { console.error(error); }); @@ -88,16 +97,27 @@ export default defineComponent({ } } }, - play() { + playPause() { this.player.addHandler('onRowChange', () => { this.$refs.progress.max = this.player.duration(); this.$refs.progress.value = this.player.position() % this.player.duration(); this.display(this.player); }); - this.player.play(this.buffer); + if (this.player.currentPlayingNode === null) { + this.player.play(this.buffer); + this.playing = true; + } else { + this.player.togglePause(); + this.playing = !this.player.currentPlayingNode.paused; + } }, stop() { this.player.stop(); + this.playing = false; + this.player.play(this.buffer); + this.display(); + this.player.stop(); + this.$refs.progress.value = 0; this.player.handlers = []; } }, @@ -147,23 +167,111 @@ export default defineComponent({ padding: 4px 8px; } - > button { + > button, a { border: none; background-color: transparent; - color: var(--accentLighten); + color: var(--accent); &:hover { background-color: var(--fg); } } + > input[type=range] { + height: 21px; + -webkit-appearance: none; + width: 90px; + padding: 0; + margin: 4px 8px; + + &:focus { + outline: none; + + &::-webkit-slider-runnable-track { + background: var(--bg); + } + + &::-ms-fill-lower, &::-ms-fill-upper { + background: var(--bg); + } + } + + &::-webkit-slider-runnable-track { + width: 100%; + height: 100%; + cursor: pointer; + border-radius: 0; + animate: 0.2s; + background: var(--bg); + border: 1px solid var(--fg); + } + + &::-webkit-slider-thumb { + border: none; + height: 100%; + width: 14px; + border-radius: 0; + background: var(--accent); + cursor: pointer; + -webkit-appearance: none; + margin-top: -0.5px; + } + + &::-moz-range-track { + width: 100%; + height: 100%; + cursor: pointer; + border-radius: 0; + animate: 0.2s; + background: var(--bg); + border: 1px solid var(--fg); + } + + &::-moz-range-thumb { + border: none; + height: 100%; + border-radius: 0; + width: 14px; + background: var(--accent); + cursoer: pointer; + } + + &::-ms-track { + width: 100%; + height: 100%; + cursor: pointer; + border-radius: 0; + animate: 0.2s; + background: transparent; + border-color: transparent; + color: transparent; + } + + &::-ms-fill-lower, &::-ms-fill-upper { + background: var(--bg); + border: 1px solid var(--fg); + border-radius: 0; + } + + &::-ms-thumb { + margin-top: 1px; + border: none; + height: 100%; + width: 14px; + border-radius: 0; + background: var(--accent); + cursor: pointer; + } + } + > progress { padding: unset; margin: 4px 8px; flex-grow: 1; + background-color: var(--bg); &::-moz-progress-bar, &::-webkit-progress-value { - background-color: var(--accentLighten); + background-color: var(--accent); } } } diff --git a/src/client/scripts/chiptune2.ts b/src/client/scripts/chiptune2.ts index 2302688c6..0b0629a35 100644 --- a/src/client/scripts/chiptune2.ts +++ b/src/client/scripts/chiptune2.ts @@ -11,10 +11,12 @@ ChiptuneJsConfig.prototype.constructor = ChiptuneJsConfig; export function ChiptuneJsPlayer (config: object) { this.config = config; - this.context = config.context || new ChiptuneAudioContext(); + this.audioContext = config.context || new ChiptuneAudioContext(); + this.context = this.audioContext.createGain(); this.currentPlayingNode = null; this.handlers = []; this.touchLocked = true; + this.volume = 1; } ChiptuneJsPlayer.prototype.constructor = ChiptuneJsPlayer; @@ -70,11 +72,12 @@ ChiptuneJsPlayer.prototype.metadata = function () { }; ChiptuneJsPlayer.prototype.unlock = function () { - const context = this.context; + const context = this.audioContext; const buffer = context.createBuffer(1, 1, 22050); const unlockSource = context.createBufferSource(); unlockSource.buffer = buffer; - unlockSource.connect(context.destination); + unlockSource.connect(this.context); + this.context.connect(context.destination); unlockSource.start(0); this.touchLocked = false; }; @@ -113,7 +116,8 @@ ChiptuneJsPlayer.prototype.play = function (buffer: ArrayBuffer) { } libopenmpt._openmpt_module_set_repeat_count(processNode.modulePtr, this.config.repeatCount || 1); this.currentPlayingNode = processNode; - processNode.connect(this.context.destination); + processNode.connect(this.context); + this.context.connect(this.audioContext.destination); }; ChiptuneJsPlayer.prototype.stop = function () { @@ -160,7 +164,7 @@ ChiptuneJsPlayer.prototype.getPatternRowChannel = function (pattern: number, row ChiptuneJsPlayer.prototype.createLibopenmptNode = function (buffer, config: object) { const maxFramesPerChunk = 4096; - const processNode = this.context.createScriptProcessor(2048, 0, 2); + const processNode = this.audioContext.createScriptProcessor(2048, 0, 2); processNode.config = config; processNode.player = this; const byteArray = new Int8Array(buffer);