Package de.sciss.swingosc

Source Code of de.sciss.swingosc.PeakMeterManager$Client

/*
*  PeakMeterManager.java
*  SwingOSC
*
*  Copyright (c) 2008-2009 Hanns Holger Rutz. All rights reserved.
*
*  This software is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either
*  version 2, june 1991 of the License, or (at your option) any later version.
*
*  This software is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public
*  License (gpl.txt) along with this software; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*
*  For further information, please contact Hanns Holger Rutz at
*  contact@sciss.de
*
*
*  Changelog:
*    11-Aug-08  created from EisK
*    21-Apr-09  created from Nuages, retrofitted java 1.4
*/
package de.sciss.swingosc;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.Timer;

import de.sciss.app.BasicEvent;
import de.sciss.app.EventManager;
import de.sciss.gui.PeakMeterView;
import de.sciss.jcollider.Bus;
import de.sciss.jcollider.Constants;
import de.sciss.jcollider.Control;
import de.sciss.jcollider.GraphElem;
import de.sciss.jcollider.Group;
import de.sciss.jcollider.OSCResponderNode;
import de.sciss.jcollider.Server;
import de.sciss.jcollider.Synth;
import de.sciss.jcollider.SynthDef;
import de.sciss.jcollider.TrigControl;
import de.sciss.jcollider.UGen;
import de.sciss.jcollider.UGenInfo;
import de.sciss.net.OSCBundle;
import de.sciss.net.OSCMessage;

/**
@author    Hanns Holger Rutz
@version  0.63, 11-Oct-09
*/
public class PeakMeterManager
implements OSCResponderNode.Action, Constants, /* ServerListener, */ ActionListener,
       EventManager.Processor
{
  private List /* <Client> */      collAllClients    = new ArrayList /* <Client> */();
  private List /* <Client> */      collActiveClients  = new ArrayList /* <Client> */();
  private Map /* <PeakMeterView,Client> */ mapClients    = new HashMap /* <PeakMeterView,Client> */();

  private Server          server        = null;
 
//  private Bus            bus          = null;
//  private Group          grp          = null;
// 
//  private int            numCtrlChans    = 0;
 
  private OSCBundle        meterBangBndl    = null;
  private OSCResponderNode    resp        = null;

  private final Timer        meterTimer;
// EEE
//  private final SuperColliderClient sc;
 
  private int            numTask        = 0;
 
  private final EventManager    elm;
 
  private final Set        defSet        = new HashSet();

  public PeakMeterManager() // ( SuperColliderClient sc ) EEE
  {
// EEE
//    this.sc    = sc;
    meterTimer  = new javax.swing.Timer( 33, this );
    elm      = new EventManager( this );
// EEE
//    sc.addServerListener( this );
  }
 
  public void setRefreshRate( int millis )
  {
    final boolean restart = meterTimer.isRunning();
    meterTimer.setDelay( millis );
    if( restart ) meterTimer.restart();
  }
 
  public void dispose()
  {
// EEE
//    sc.removeServerListener( this );
    disposeServer();
  }

  private void meterBang()
  {
    if( (server != null) && (meterBangBndl != null) ) {
      try {
        server.sendBundle( meterBangBndl );
      }
      catch( IOException e1 ) { /* don't print coz the frequency might be high */ }
    }
  }

  // ------------- ActionListener interface -------------

  public void actionPerformed( ActionEvent e )
  {
    meterBang();
  }

//  // ------------- ServerListener interface -------------
//
//  public void serverAction( ServerEvent e )
//  {
//    switch( e.getID() ) {
//    case ServerEvent.STOPPED:
//      setServer( null );
//      break;
//     
//    case ServerEvent.RUNNING:
//      setServer( e.getServer() );
//      break;
//     
//    default:
//      break;
//    }
//  }

  // ----------------- OSCListener interface -----------------
 
  public void respond( OSCResponderNode r, OSCMessage msg, long time )
  {
    elm.dispatchEvent( new Event( r, msg, time ));
  }

  // ----------------- EventManager.Processor interface -----------------

  public void processEvent( BasicEvent be )
  {
    final Event      e      = (Event) be;
    final OSCMessage  msg      = e.msg;
//    final int      busIndex  = ((Number) msg.getArg( 0 )).intValue();
//    final int      numVals    = ((Number) msg.getArg( 1 )).intValue();
// getWhen doesn't provide a valid value i think
//    final long      time    = e.getWhen();
    final long      time    = System.currentTimeMillis();
    Client        mc; 
 
//    if( (bus == null) || (busIndex != bus.getIndex()) ) return;

    for( int i = 0, off = 0; i < collActiveClients.size(); i++ ) {
      mc  = (Client) collActiveClients.get( i );
      if( (((Number) msg.getArg( off++ )).intValue() != mc.ctrlBus.getIndex()) ||
        (((Number) msg.getArg( off++ )).intValue() != mc.ctrlBus.getNumChannels()) ) return;
      if( mc.task ) {
        if( mc.monoSum ) {
          mc.peakRMSPairs[ 0 ] = ((Number) msg.getArg( off++ )).floatValue();
          mc.peakRMSPairs[ 1 ] = ((Number) msg.getArg( off++ )).floatValue();
        } else {
          for( int j = 0, k = 0; k < mc.srcChans.length; k++) {
            if( mc.srcChans[ k ] >= 0 ) {
              mc.peakRMSPairs[ j++ ] = ((Number) msg.getArg( off++ )).floatValue();
              mc.peakRMSPairs[ j++ ] = ((Number) msg.getArg( off++ )).floatValue();
            } else {
              mc.peakRMSPairs[ j++ ] = 0f;
              mc.peakRMSPairs[ j++ ] = 0f;
              off += 2;
            }
          }
        }
      } else {
        off += mc.ctrlBus.getNumChannels();
      }
    }
   
    for( int i = 0; i < collActiveClients.size(); i++ ) {
      mc = (Client) collActiveClients.get( i );
      if( mc.task ) mc.view.meterUpdate( mc.peakRMSPairs, 0, time );
    }
  }

  private static void printError( String name, Throwable t )
  {
    System.err.println( name + " : " + t.getClass().getName() + " : " + t.getLocalizedMessage() );
  }

  private void disposeServer()
  {
    Client mc;

    meterTimer.stop();
   
    if( resp != null ) resp.remove();
   
    if( server == null ) return;
   
    for( int i = 0; i < collAllClients.size(); ) {
      mc = (Client) collAllClients.get( i );
      if( mc.server == server ) {
        collAllClients.remove( i );
      } else {
        i++;
      }
    }

    collActiveClients.clear();
    server      = null;
    meterBangBndl  = null;
   
    defSet.clear();
  }
 
  public void setServer( Server s )
  {
    disposeServer();
 
    if( s == null ) return;

    server = s;
       
    for( int i = 0; i < collAllClients.size(); i++ ) {
      final Client mc = (Client) collAllClients.get( i );
      if( mc.server == server ) {
        collActiveClients.add( mc );
      }
    }
       
    resp = new OSCResponderNode( server, "/c_setn", this );
    resortClients();
   
    // XXX playToBundle ...
  }
 
  public void setListenerTask( PeakMeterView view, boolean task )
  {
    setListenerTask( view, task, null );
  }
 
  public void setListenerTask( PeakMeterView view, boolean task, OSCBundle bndl )
  {
    if( !EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();

    final Client mc = (Client) mapClients.get( view );
    if( mc == null ) return;
    if( mc.task != task ) {
      mc.task  = task;
      if( mc.server == server ) {
        final boolean weCreated = bndl == null;
        if( weCreated ) bndl = new OSCBundle();
        for( int j = 0; j < mc.synths.length; j++ ) {
          if( mc.synths[ j ] != null ) {
            bndl.addPacket( mc.synths[ j ].runMsg( task ));
          }
        }
        if( weCreated && (bndl.getPacketCount() > 0) ) {
          try {
            server.sendBundle( bndl );
          }
          catch( IOException e1 ) {
            printError( "setListenerTask", e1 );
          }
        }
        if( task ) {
          if( ++numTask == 1 ) {
            meterTimer.restart();
          }
        } else {
          if( --numTask == 0 ) {
            meterTimer.stop();
          }
        }
      }
    }
  }

  public void addListener( PeakMeterView view, Bus audioBus, Group g, Bus ctrlBus,
               boolean task )
  {
    addListener( view, audioBus, g, ctrlBus, task, true, -1 );
  }
 
  public void addListener( PeakMeterView view, Bus audioBus, Group g, Bus ctrlBus,
               boolean task, int nodeID )
  {
    addListener( view, audioBus, g, ctrlBus, task, true, nodeID );
  }
 
  public void addListener( PeakMeterView view, Bus audioBus, Group g, Bus ctrlBus,
               boolean task, boolean synthDef, int nodeID )
  {
    final int[] channels = new int[ audioBus.getNumChannels() ];

    for( int i = 0, j = audioBus.getIndex(); i < channels.length; ) {
      channels[ i++ ] = j++;
    }
    addListener( view, audioBus.getServer(), channels, g, ctrlBus, task, synthDef, nodeID );
  }

  public void addListener( PeakMeterView view, Server s, int[] channels, Group g,
               Bus ctrlBus, boolean task, boolean synthDef, int nodeID )
  {
    final Client mc;

    if( !EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();
 
    mc = new Client( view, s, channels, g, ctrlBus, task, synthDef, nodeID );
    if( mapClients.put( view, mc ) != null ) throw new IllegalArgumentException( "MeterListener was already registered" );
    collAllClients.add( mc );
    if( mc.server == server ) {
      collActiveClients.add( mc );
      resortClients();
      final OSCBundle bndl = new OSCBundle();
      try {
        playToBundle( bndl, mc );
        if( bndl.getPacketCount() > 0 ) {
          server.sendBundle( bndl );
          if( (resp != null) && !resp.isListening() ) resp.add();
          if( numTask > 0 ) meterTimer.restart();
        }
      }
      catch( IOException e1 ) {
        printError( "addListener", e1 );
      }
    }
  }
 
  private void playToBundle( OSCBundle bndl, Client mc )
  throws IOException
  {
    if( mc.monoSum && (mc.srcChans.length > 0) ) {
      mc.synths[ 0 ] = Synth.basicNew( "swing-peak" + mc.srcChans.length, server,
                                       mc.nodeID == -1 ? server.nextNodeID() : mc.nodeID );
      bndl.addPacket( mc.synths[ 0 ].newMsg( mc.g, new String[] {
        "i_kOtBs" }, new float[] { mc.ctrlBus.getIndex() }, kAddToTail ));
      final float[][] chans = new float[ 1 ][ mc.srcChans.length ];
      for( int i = 0; i < mc.srcChans.length; i++ ) { // no cast from int[] to float[]...
        chans[ 0 ][ i ] = mc.srcChans[ i ];
//        System.out.println( "chans[ 0 ][ " + i + " ] = " + chans[ 0 ][ i ]);
      }
      bndl.addPacket( mc.synths[ 0 ].setnMsg( new String[] { "i_aInBs" }, chans ));
      if( !mc.task ) {
        bndl.addPacket( mc.synths[ 0 ].runMsg( false ));
      }
      mc.synths[ 0 ].register();
    } else {
      for( int j = 0, m = mc.ctrlBus.getIndex(); j < mc.synths.length; j++, m += 2 ) {
        if( mc.srcChans[ j ] >= 0 ) {
          mc.synths[ j ] = Synth.basicNew( "swing-peak1", server,
                                           mc.nodeID == -1 ? server.nextNodeID() : (mc.nodeID + j) );
          bndl.addPacket( mc.synths[ j ].newMsg( mc.g, new String[] {
            "i_aInBs",        "i_kOtBs" }, new float[] {
            mc.srcChans[ j ], m }, kAddToTail ));
          if( !mc.task ) {
            bndl.addPacket( mc.synths[ j ].runMsg( false ));
          }
          mc.synths[ j ].register();
        }
      }
    }
  }
 
  private void stopToBundle( OSCBundle bndl, Client mc )
  {
    for( int i = 0; i < mc.synths.length; i++ ) {
      if( mc.synths[ i ] != null ) {
        bndl.addPacket( mc.synths[ i ].freeMsg() );
        mc.synths[ i ] = null;
      }
    }
  }
 
  private SynthDef createDef( int numChannels )
  throws IOException
  {
    if( UGenInfo.infos == null ) UGenInfo.readBinaryDefinitions();
   
    final Control    i_aInBs  = Control.ir( "i_aInBs", new float[ numChannels ]);
    final GraphElem    i_kOtBs  = Control.ir( "i_kOtBs" );
    final GraphElem    t_trig  = TrigControl.kr( "t_trig" );
    final GraphElem    in    = UGen.ar( "In", i_aInBs );
    GraphElem      rms    = UGen.ar( "Lag", UGen.ar( "squared", in ), UGen.ir( 0.1f ));
//    GraphElem      peak  = UGen.ar( "Peak", in, t_trig );
    GraphElem      trigA  = UGen.ar( "Trig1", t_trig, UGen.ir( "SampleDur" ));
//    GraphElem      peak  = UGen.ar( "Peak", in, trigA );
    GraphElem      peak  = UGen.kr( "Peak", in, trigA );
    final GraphElem    out;
    final SynthDef    def;
    GraphElem      temp;

    if( numChannels > 1 ) {
      temp = peak;
      peak = temp.getOutput( 0 );
      for( int i = 1; i < numChannels; i++ ) {
//        peak = UGen.ar( "max", peak, temp.getOutput( i ));
        peak = UGen.kr( "max", peak, temp.getOutput( i ));
      }
      temp = rms;
      rms  = temp.getOutput( 0 );
      for( int i = 1; i < numChannels; i++ ) {
        rms = UGen.ar( "+", rms, temp.getOutput( i ));
      }
      rms = UGen.ar( "*", rms, UGen.ir( 1.0f / numChannels ));
    }

    // we are reading the values asynchronously through
    // a /c_getn on the meter bus. each request is followed
    // by a /n_set to re-trigger the latch so that we are
    // not missing any peak values.
//    out = UGen.kr( "Out", i_kOtBs, UGen.array( UGen.kr( "Latch", peak, t_trig ), rms ));
    out = UGen.kr( "Out", i_kOtBs, UGen.array( peak, rms ));
   
    def = new SynthDef( "swing-peak" + numChannels, out );
//    def.writeDefFile( new java.io.File( "/Users/rutz/Desktop/meters.scsyndef" ));
    return def;
  }
 
  public void removeListener( PeakMeterView view )
  {
    final Client    mc;
    final OSCBundle    bndl;
   
    if( !EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();

    mc = (Client) mapClients.remove( view );
    if( mc == null ) return;
    collAllClients.remove( mc );
    if( collActiveClients.remove( mc )) {
      bndl = new OSCBundle();
      stopToBundle( bndl, mc );
      if( bndl.getPacketCount() > 0 ) {
        try {
          if( server.isRunning() ) server.sendBundle( bndl );
          resortClients();
        }
        catch( IOException e1 ) {
          printError( "removeMeterListener", e1 );
        }
      }
    }
  }
 
  private void resortClients()
  {
    numTask  = 0;
   
    if( server == null ) {
      meterTimer.stop();
      if( resp != null ) resp.remove();
      meterBangBndl = null;
      return;
    }
   
    final Integer[] cgetnArgs = new Integer[ collActiveClients.size() << 1 ];
   
    meterBangBndl = new OSCBundle();
    final OSCBundle defBndl = new OSCBundle();
   
    for( int i = 0, k = 0; i < collActiveClients.size(); i++ ) {
      final Client mc = (Client) collActiveClients.get( i );
      if( mc.task ) numTask++;
      meterBangBndl.addPacket( new OSCMessage( "/n_set", new Object[] {
        new Integer( mc.g.getNodeID() ), "t_trig", new Integer( 1 )}));
      cgetnArgs[ k++ ] = new Integer( mc.ctrlBus.getIndex() );
      cgetnArgs[ k++ ] = new Integer( mc.ctrlBus.getNumChannels() );
     
      if( mc.synthDef ) {
        final int numChannels = mc.monoSum ? mc.srcChans.length : 1;
        if( numChannels > 0 ) {
          final Object key = new Integer( numChannels );
          if( !defSet.contains( key )) {
            try {
              defBndl.addPacket( createDef( numChannels ).recvMsg() );
              defSet.add( key );
            }
            catch( IOException e1 ) {
              printError( "resortClients", e1 );
            }
          }
        }
      }
    }
    meterBangBndl.addPacket( new OSCMessage( "/c_getn", cgetnArgs ));
   
    try {
      if( defBndl.getPacketCount() > 0 ) {
        server.sync( defBndl, 4f );
      }
      if( (resp != null) && !resp.isListening() ) resp.add();
      if( numTask == 0 ) {
        meterTimer.stop();
      } else {
        meterTimer.start();
      }
    }
    catch( IOException e1 ) {
      printError( "resortClients", e1 );
    }
  }

  // ------------- internal classes -------------
 
  private static class Event
  extends BasicEvent
  {
    protected OSCMessage msg;
   
    protected Event( Object src, OSCMessage msg, long time )
    {
      super( src, 0, time );
      this.msg = msg;
    }

    public boolean incorporate( BasicEvent oldEvent )
    {
      if( (oldEvent instanceof Event) && (oldEvent.getSource() == getSource()) ) {
        final OSCMessage omsg = ((Event) oldEvent).msg;
        if( omsg.getName().equals( msg.getName() ) &&
          (omsg.getArgCount() == msg.getArgCount()) &&
          omsg.getArg( 0 ).equals( msg.getArg( 0 )) &&  // busIndex
          omsg.getArg( 1 ).equals( msg.getArg( 1 ))) {  // numVals
         
          final Object[] fuseArgs = new Object[ msg.getArgCount() ];
          fuseArgs[ 0 ] = msg.getArg( 0 );
          fuseArgs[ 1 ] = msg.getArg( 1 );
          for( int i = 2; i < fuseArgs.length; i++ ) {
            fuseArgs[ i ] = new Float( Math.max(
                ((Numbermsg.getArg( i )).floatValue(),
                ((Number) omsg.getArg( i )).floatValue() ));
          }
          msg = new OSCMessage( msg.getName(), fuseArgs );
          return true;
        }
      }
      return false;
    }
  }
 
  private static class Client
  {
    protected final float[]      peakRMSPairs;
    protected final PeakMeterView  view;
    protected final int[]      srcChans;
    protected final Group      g;
    protected final Bus        ctrlBus;
    protected final boolean      monoSum;
    protected final Synth[]      synths;
    protected final Server      server;
    protected boolean        task;
    protected final boolean      synthDef;
    protected final int        nodeID;
   
    protected Client( PeakMeterView view, Server server, int[] srcChans, Group g,
              Bus ctrlBus, boolean task, boolean synthDef, int nodeID )
    {
      this.view    = view;
      this.server    = server;
      this.srcChans  = srcChans;
      this.g      = g;
      this.ctrlBus  = ctrlBus;
      this.task    = task;
      this.synthDef  = synthDef;
      this.nodeID    = nodeID;
     
//      System.out.print( "new Client() -> srcChans = " );
//      for( int i = 0; i < srcChans.length; i++ ) {
//        System.out.print(  (i == 0 ? "[ " : ", ") + srcChans[ i ]);
//      }
//      System.out.println( " ]" );

      peakRMSPairs  = new float[ ctrlBus.getNumChannels() ];
      monoSum      = (peakRMSPairs.length == 2) && (srcChans.length > 1);
      if( !monoSum && (peakRMSPairs.length != (srcChans.length << 1)) ) {
        throw new IllegalArgumentException( "Audio/Control Bus Channel Mismatch (" + srcChans.length + " vs. " + peakRMSPairs.length + ")" );
      }
      synths      = new Synth[ peakRMSPairs.length >> 1 ];
    }
   
    public String toString()
    {
      final StringBuffer sb = new StringBuffer();
      sb.append( "[ " );
      for( int i = 0; i < srcChans.length; i++ ) {
        if( i > 0 ) sb.append( ", " );
        sb.append( srcChans[ i ]);
      }
      sb.append( " ]" );
      return( "MeterClient( "+view+", "+server+", " + sb.toString() + ", " + g + ", " + task + " )" );
    }
  }
}
TOP

Related Classes of de.sciss.swingosc.PeakMeterManager$Client

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.