All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sciss.mellite.gui.impl.audiofile.ViewImpl.scala Maven / Gradle / Ivy

/*
 *  ViewImpl.scala
 *  (Mellite)
 *
 *  Copyright (c) 2012-2016 Hanns Holger Rutz. All rights reserved.
 *
 *  This software is published under the GNU General Public License v3+
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.mellite
package gui
package impl
package audiofile

import java.awt.datatransfer.Transferable

import de.sciss.audiowidgets.TimelineModel
import de.sciss.audiowidgets.impl.TimelineModelImpl
import de.sciss.desktop.impl.UndoManagerImpl
import de.sciss.file._
import de.sciss.lucre.artifact.{Artifact, ArtifactLocation}
import de.sciss.lucre.stm
import de.sciss.lucre.swing._
import de.sciss.lucre.swing.impl.ComponentHolder
import de.sciss.lucre.synth.Sys
import de.sciss.mellite.gui.impl.component.DragSourceButton
import de.sciss.span.Span
import de.sciss.synth.SynthGraph
import de.sciss.synth.proc.graph.ScanIn
import de.sciss.synth.proc.gui.TransportView
import de.sciss.synth.proc.{AudioCue, AuralSystem, Proc, TimeRef, Timeline, Transport, WorkspaceHandle}
import de.sciss.{sonogram, synth}

import scala.swing.Swing._
import scala.swing.{BorderPanel, BoxPanel, Component, Label, Orientation}

object ViewImpl {
  def apply[S <: Sys[S]](obj0: AudioCue.Obj[S])
                        (implicit tx: S#Tx, _workspace: Workspace[S], _cursor: stm.Cursor[S],
                         aural: AuralSystem): AudioFileView[S] = {
    val audioCue      = obj0
    val audioCueV     = audioCue.value // .artifact // store.resolve(element.entity.value.artifact)
    // val sampleRate    = f.spec.sampleRate
    type I            = _workspace.I
    import _workspace.inMemoryBridge
    implicit val itx  = inMemoryBridge(tx)
    val timeline      = Timeline[I] // proc.ProcGroup.Modifiable[I]
    // val groupObj      = Obj(ProcGroupElem(group))
    val srRatio       = audioCueV.spec.sampleRate / TimeRef.SampleRate
    // val fullSpanFile  = Span(0L, f.spec.numFrames)
    val numFramesTL   = (audioCueV.spec.numFrames / srRatio).toLong
    val fullSpanTL    = Span(0L, numFramesTL)

    // ---- we go through a bit of a mess here to convert S -> I ----
     val artifact      = obj0.value.artifact
     val artifDir      = artifact.parent //  artifact.location.directory
     val iLoc          = ArtifactLocation.newVar[I](artifDir)
     val iArtifact     = Artifact(iLoc, artifact) // iLoc.add(artifact.value)

    val iGrapheme     = AudioCue.Obj[I](iArtifact, audioCueV.spec, audioCueV.offset, audioCueV.gain)

    val (_, proc)     = ProcActions.insertAudioRegion[I](timeline, time = Span(0L, numFramesTL),
      /* track = 0, */ audioCue = iGrapheme, gOffset = 0L /* , bus = None */)

    val diff = Proc[I]
    val diffGr = SynthGraph {
      import synth._
      import ugen._
      val in0 = ScanIn(Proc.mainIn)
      // in0.poll(1, "audio-file-view")
      val in = if (audioCueV.numChannels == 1) Pan2.ar(in0) else in0  // XXX TODO
      Out.ar(0, in) // XXX TODO
    }
    diff.graph() = diffGr

    val output = proc.outputs.add(Proc.mainOut)
    diff.attr.put(Proc.mainIn, output)

    import _workspace.inMemoryCursor
    // val transport     = Transport[I, I](group, sampleRate = sampleRate)
    import WorkspaceHandle.Implicits._
    val transport = Transport[I](aural)
    transport.addObject(timeline) // Obj(Timeline(timeline)))
    transport.addObject(diff)

    implicit val undoManager = new UndoManagerImpl
    // val offsetView  = LongSpinnerView  (grapheme.offset, "Offset")
    val gainView    = DoubleSpinnerView[S](audioCue.value.gain /* RRR */, "Gain", width = 90)
    val res: Impl[S, I] = new Impl[S, I](gainView = gainView) {
      val timelineModel = new TimelineModelImpl(fullSpanTL, TimeRef.SampleRate)
      val workspace     = _workspace
      val cursor        = _cursor
      val holder        = tx.newHandle(obj0)
      val transportView: TransportView[I] = TransportView[I](transport, timelineModel, hasMillis = true, hasLoop = true)
    }

    deferTx {
      res.guiInit(audioCueV)
    } (tx)
    res
  }

  private abstract class Impl[S <: Sys[S], I <: Sys[I]](gainView: View[S])(implicit inMemoryBridge: S#Tx => I#Tx)
    extends AudioFileView[S] with ComponentHolder[Component] { impl =>

    protected def holder       : stm.Source[S#Tx, AudioCue.Obj[S]]
    protected def transportView: TransportView[I]
    protected def timelineModel: TimelineModel

    private var _sonogram: sonogram.Overview = _

    def dispose()(implicit tx: S#Tx): Unit = {
      val itx: I#Tx = tx
      transportView.transport.dispose()(itx)
      transportView.dispose()(itx)
      gainView     .dispose()
      deferTx {
        SonogramManager.release(_sonogram)
      }
    }

    def guiInit(snapshot: AudioCue): Unit = {
      // println("AudioFileView guiInit")
      _sonogram = SonogramManager.acquire(snapshot.artifact)
      // import SonogramManager.executionContext
      //      sono.onComplete {
      //        case x => println(s" $x")
      //      }
      val sonogramView = new ViewJ(_sonogram, timelineModel)

      // val ggDragRegion = new DnD.Button(holder, snapshot, timelineModel)
      val ggDragRegion = new DragSourceButton() {
        protected def createTransferable(): Option[Transferable] = {
          val sp    = timelineModel.selection match {
            case sp0: Span if sp0.nonEmpty =>  sp0
            case _ => timelineModel.bounds
          }
          val drag  = timeline.DnD.AudioDrag(workspace, holder, selection = sp)
          val t     = DragAndDrop.Transferable(timeline.DnD.flavor)(drag)
          Some(t)
        }
        tooltip = "Drag Selected Region"
      }

      val topPane = new BoxPanel(Orientation.Horizontal) {
        contents ++= Seq(
          HStrut(4),
          ggDragRegion,
          // new BusSinkButton[S](impl, ggDragRegion),
          HStrut(4),
          new Label("Gain:"),
          gainView.component,
          HGlue,
          HStrut(4),
          transportView.component,
          HStrut(4)
        )
      }

      val pane = new BorderPanel {
        layoutManager.setVgap(2)
        add(topPane,                BorderPanel.Position.North )
        add(sonogramView.component, BorderPanel.Position.Center)
      }

      component = pane
      // sonogramView.component.requestFocus()
    }

    def obj(implicit tx: S#Tx): AudioCue.Obj[S] = holder()
  }

  //  private final class BusSinkButton[S <: Sys[S]](view: AudioFileView[S], export: Button)
  //    extends Button("Drop bus") {
  //
  //    icon        = new ImageIcon(Mellite.getClass.getResource("dropicon16.png"))
  //    // this doesn't have any effect?
  //    // GUI.fixWidth(this)
  //    foreground  = Color.gray
  //    focusable   = false
  //
  //    // private var item = Option.empty[stm.Source[S#Tx, Element.Int[S]]]
  //
  //    private val trns = new TransferHandler {
  //      // how to enforce a drop action: https://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html
  //      override def canImport(support: TransferSupport): Boolean =
  //        if (support.isDataFlavorSupported(FolderView.SelectionFlavor) &&
  //           ((support.getSourceDropActions & TransferHandler.COPY) != 0)) {
  //          support.setDropAction(TransferHandler.COPY)
  //          true
  //        } else false
  //
  //      override def importData(support: TransferSupport): Boolean = {
  //        val t     = support.getTransferable
  //        val data  = t.getTransferData(FolderView.SelectionFlavor).asInstanceOf[FolderView.SelectionDnDData[S]]
  //        (data.workspace == view.workspace) && {
  //          data.selection.exists { nodeView =>
  //            nodeView.renderData match {
  //              case ev: ObjView.Int[S] =>
  //                // export.bus  = Some(ev.obj)
  //                text        = ev.name
  //                foreground  = null
  //                repaint()
  //                true
  //
  //              case _ => false
  //            }
  //          }
  //        }
  //      }
  //    }
  //    peer.setTransferHandler(trns)
  //  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy