Changeset - 1dc96b97a544
[Not reviewed]
default
0 5 0
drewp@bigasterisk.com - 3 years ago 2022-06-03 07:41:13
drewp@bigasterisk.com
two zoomed spectrogram views in asco
5 files changed with 95 insertions and 49 deletions:
0 comments (0 inline, 0 general)
light9/ascoltami/Light9AscoltamiUi.ts
Show inline comments
 
import debug from "debug";
 
import { html, LitElement } from "lit";
 
import { css, html, LitElement } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
@@ -8,6 +8,7 @@ export { RdfdbSyncedGraph } from "../web
 
export { Light9TimelineAudio } from "../web/light9-timeline-audio";
 
import { classMap } from "lit/directives/class-map.js";
 
import { TimingUpdate } from "./main";
 
import { Zoom } from "../web/light9-timeline-audio";
 

	
 
debug.enable("*");
 
const log = debug("asco");
 
@@ -28,9 +29,22 @@ export class Light9AscoltamiUi extends L
 
  times!: { intro: number; post: number };
 
  @property() nextText: string = "";
 
  @property() isPlaying: boolean = false;
 
  @property() show: NamedNode | null = null;
 
  @property() song: NamedNode | null = null;
 
  @property() t: number = 0;
 
  @property() currentDuration: number = 0;
 
  @property() zoom: Zoom;
 
  @property() overviewZoom: Zoom;
 
  static styles = [
 
    css`
 
      .timeRow {
 
        margin: 14px;
 
      }
 
      light9-timeline-audio {
 
        height: 80px;
 
      }
 
    `,
 
  ];
 
  render() {
 
    return html`<rdfdb-synced-graph></rdfdb-synced-graph>
 

	
 
@@ -38,6 +52,12 @@ export class Light9AscoltamiUi extends L
 

	
 
      <h1>ascoltami <a href="metrics">[metrics]</a></h1>
 

	
 
      <div class="timeRow">
 
        <div id="timeSlider"></div>
 
        <light9-timeline-audio .show=${this.show} .song=${this.song} .zoom=${this.overviewZoom}></light9-timeline-audio>
 
        <light9-timeline-audio .show=${this.show} .song=${this.song} .zoom=${this.zoom}></light9-timeline-audio>
 
      </div>
 

	
 
      <div class="commands">
 
        <button id="cmd-stop" @click=${this.onCmdStop} class="playMode ${classMap({ active: !this.isPlaying })}">
 
          <strong>Stop</strong>
 
@@ -106,13 +126,10 @@ export class Light9AscoltamiUi extends L
 
    });
 
  }
 

	
 
  currentDurationChanged(newDuration: number): void {
 
    this.currentDuration = newDuration;
 
  }
 

	
 
  async musicSetup() {
 
    // shoveled over from the vanillajs version
 
    const config = await (await fetch("api/config")).json();
 
    this.show = new NamedNode(config.show);
 
    this.times = config.times;
 
    document.title = document.title.replace("{{host}}", config.host);
 
    const h1 = document.querySelector("h1")!;
 
@@ -130,14 +147,16 @@ export class Light9AscoltamiUi extends L
 
      this.nextText = data.next;
 
      this.isPlaying = data.playing;
 
      this.currentDuration = data.duration;
 
      this.song = new NamedNode(data.song);
 
      this.overviewZoom = { duration: data.duration, t1: 0, t2: data.duration };
 
      this.zoom = { duration: data.duration, t1: data.t - 2, t2: data.t + 20 };
 
    });
 
  }
 

	
 
  constructor() {
 
    super();
 
    this.bindKeys();
 
    //   byId("cmd-stop").addEventListener("click", (ev: Event) =>
 
    // );
 
    this.zoom = this.overviewZoom = { duration: null, t1: 0, t2: 1 };
 

	
 
    getTopGraph().then((g) => {
 
      this.graph = g;
light9/ascoltami/index.html
Show inline comments
 
@@ -36,9 +36,6 @@
 
        </tr>
 
      </table>
 

	
 
      <div class="timeRow">
 
        <div id="timeSlider"></div>
 
      </div>
 
    </div>
 

	
 
    <hr />
light9/ascoltami/webapp.py
Show inline comments
 
@@ -10,7 +10,7 @@ import cyclone.websocket
 
from cycloneerr import PrettyErrorHandler
 
from light9.metrics import metricsRoute
 
from light9.namespaces import L9
 
from light9.showconfig import getSongsFromShow, songOnDisk
 
from light9.showconfig import getSongsFromShow, showUri, songOnDisk
 
from rdflib import URIRef
 
from twisted.internet import reactor
 
from twisted.internet.interfaces import IReactorTime
 
@@ -36,6 +36,7 @@ class config(cyclone.web.RequestHandler)
 
        self.write(
 
            json.dumps(dict(
 
                host=socket.gethostname(),
 
                show=str(showUri()),
 
                times={
 
                    # these are just for the web display. True values are on Player.__init__
 
                    'intro': 4,
light9/web/light9-timeline-audio.ts
Show inline comments
 
import { debug } from "debug";
 

	
 
import { css, html, LitElement, TemplateResult } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
 
import { customElement, property, state } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { loadConfigFromFile } from "vite";
 
import { getTopGraph } from "./RdfdbSyncedGraph";
 
import { SyncedGraph } from "./SyncedGraph";
 

	
 
const log = debug("audio");
 

	
 
export interface Zoom {
 
  duration: number | null;
 
  t1: number;
 
  t2: number;
 
}
 

	
 
function nodeHasChanged(newVal?: NamedNode, oldVal?: NamedNode): boolean {
 
  if (newVal === undefined && oldVal === undefined) {
 
    return false;
 
  }
 
  if (newVal === undefined || oldVal === undefined) {
 
    return true;
 
  }
 
  return !newVal.equals(oldVal);
 
}
 

	
 
// (potentially-zoomed) spectrogram view
 
@customElement("light9-timeline-audio")
 
export class Light9TimelineAudio extends LitElement {
 
  graph!: SyncedGraph;
 
  render() {
 
    return html`
 
      <style>
 
@@ -25,56 +46,67 @@ export class Light9TimelineAudio extends
 
        img {
 
          height: 100%;
 
          position: relative;
 
          transition: left .1s linear;
 

	
 
        }
 
      </style>
 
      <div>
 
        <img src="{{imgSrc}}" style="width: {{imgWidth}} ; left: {{imgLeft}}" />
 
        <img src=${this.imgSrc} style="width: ${this.imgWidth}; left: ${this.imgLeft}" />
 
      </div>
 
    `;
 
  }
 
  //    properties= {
 
  //        graph: {type: Object, notify: true},
 
  //        show: {type: String, notify: true},
 
  //        song: {type: String, notify: true},
 
  //        zoom: {type: Object, notify: true},
 
  //        imgSrc: { type: String, notify: true},
 
  //        imgWidth: { computed: '_imgWidth(zoom)' },
 
  //        imgLeft: { computed: '_imgLeft(zoom)' },
 
  //    }
 
  //    observers= [
 
  //        'setImgSrc(graph, show, song)'
 
  //    ]
 
  ready() {
 
    this.zoom = { duration: 0 };
 
  @property({ hasChanged: nodeHasChanged }) show!: NamedNode;
 
  @property({ hasChanged: nodeHasChanged }) song!: NamedNode;
 
  @property() zoom: Zoom = { duration: null, t1: 0, t2: 1 };
 
  @state() imgSrc: string = "#";
 
  @state() imgWidth: string = "0"; // css
 
  @state() imgLeft: string = "0"; // css
 

	
 
  constructor() {
 
    super();
 

	
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
    });
 
  }
 

	
 
  updated(changedProperties: PropertyValues) {
 
    if (changedProperties.has("song") || changedProperties.has("show")) {
 
      if (this.song && this.show) {
 
        this.graph.runHandler(this.setImgSrc.bind(this), "timeline-audio " + this.song);
 
      }
 
    }
 
    if (changedProperties.has("zoom")) {
 
      this.imgWidth = this._imgWidth(this.zoom);
 
      this.imgLeft = this._imgLeft(this.zoom);
 
    }
 
  }
 

	
 
  setImgSrc() {
 
    graph.runHandler(
 
      function () {
 
        try {
 
          var root = this.graph.stringValue(this.graph.Uri(this.show), this.graph.Uri(":spectrogramUrlRoot"));
 
        } catch (e) {
 
          return;
 
        }
 
    try {
 
      var root = this.graph.stringValue(this.show, this.graph.Uri(":spectrogramUrlRoot"));
 
    } catch (e) {
 
      return;
 
    }
 

	
 
        try {
 
          var filename = this.graph.stringValue(this.song, this.graph.Uri(":songFilename"));
 
        } catch (e) {
 
          return;
 
        }
 
    try {
 
      var filename = this.graph.stringValue(this.song, this.graph.Uri(":songFilename"));
 
    } catch (e) {
 
      return;
 
    }
 

	
 
        this.imgSrc = root + "/" + filename.replace(".wav", ".png").replace(".ogg", ".png");
 
      }.bind(this),
 
      "timeline-audio " + this.song
 
    );
 
    this.imgSrc = root + "/" + filename.replace(".wav", ".png").replace(".ogg", ".png");
 
    log(`imgSrc ${this.imgSrc}`);
 
  }
 
  _imgWidth(zoom) {
 

	
 
  _imgWidth(zoom: Zoom): string {
 
    if (!zoom.duration) {
 
      return "100%";
 
    }
 

	
 
    return 100 / ((zoom.t2 - zoom.t1) / zoom.duration) + "%";
 
  }
 
  _imgLeft(zoom) {
 
  _imgLeft(zoom: Zoom): string {
 
    if (!zoom.duration) {
 
      return "0";
 
    }
light9/web/style.css
Show inline comments
 
@@ -98,9 +98,6 @@ div.keys {
 
  background: #a90707;
 
}
 

	
 
.timeRow {
 
  margin: 14px;
 
}
 

	
 
.stalled {
 
  opacity: 0.5;
0 comments (0 inline, 0 general)