Files @ 06da5db2fafe
Branch filter:

Location: light9/web/light9-timeline-audio.ts - annotation

drewp@bigasterisk.com
rewrite ascoltami to use the graph for more playback data
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
06da5db2fafe
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
06da5db2fafe
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
06da5db2fafe
06da5db2fafe
4556eebe5d73
06da5db2fafe
4556eebe5d73
06da5db2fafe
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
import { debug } from "debug";
import { html, LitElement, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { NamedNode } from "n3";
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;
  graphReady: Promise<void>;
  render() {
    return html`
      <style>
        :host {
          display: block;
          /* shouldn't be seen, but black is correct for 'no
         audio'. Maybe loading stripes would be better */
          background: #202322;
        }
        div {
          width: 100%;
          height: 100%;
          overflow: hidden;
        }
        img {
          height: 100%;
          position: relative;
          transition: left 0.1s linear;
        }
      </style>
      <div>
        <img src=${this.imgSrc} style="width: ${this.imgWidth}; left: ${this.imgLeft}" />
      </div>
    `;
  }
  @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();

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

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

  setImgSrc() {
    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;
    }

    this.imgSrc = root + "/" + filename.replace(".wav", ".png").replace(".ogg", ".png");
    log(`imgSrc ${this.imgSrc}`);
  }

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

    return 100 / ((zoom.t2 - zoom.t1) / zoom.duration) + "%";
  }
  _imgLeft(zoom: Zoom): string {
    if (!zoom.duration) {
      return "0";
    }

    var percentPerSec = 100 / (zoom.t2 - zoom.t1);
    return -percentPerSec * zoom.t1 + "%";
  }
}