/*
* Buffer.java
* JCollider
*
* Copyright (c) 2004-2010 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 , or visit http://www.sciss.de/jcollider
*
*
* JCollider is closely modelled after SuperCollider Language,
* often exhibiting a direct translation from Smalltalk to Java.
* SCLang is a software originally developed by James McCartney,
* which has become an Open Source project.
* See http://supercollider.sourceforge.net/ for details.
*
*
* Changelog:
* 04-Aug-05 created
* 14-Aug-05 fixes freeMsg and freeAll (omitted buffer-allocator free calls)
* 07-Oct-05 added missing /b_write support
* 31-Jul-06 added play methods ; exchanged CompletionFunction against OSCMessage were
* it wasn't making sense + removed CompletionMessage class
* ; static allocation methods now return <code>null</code>
* if allocation fails (just like <code>Bus</code> does)
* ; the readNoUpdate signature has been changed to have bufNum
* appear as the last argument
* 02-Sep-06 fixed null pointer exceptions when competionFunc == null
*/
package de.sciss.jcollider;
import java.io.IOException;
import java.io.PrintStream;
import de.sciss.net.OSCBundle;
import de.sciss.net.OSCMessage;
/**
* Mimics SCLang's Buffer class,
* that is, it's a client side
* representation of an audio buffer
*
* @warning this is a quick direct translation from SClang
* which is largely untested. before all methods have been
* thoroughly verified, excepted some of them to be wrong
* or behave different than expected. what certainly works
* is alloc-, read-, free-, zero- and close-messages
*
* @author Hanns Holger Rutz
* @version 0.32, 25-Feb-08
*
* @todo custom fill commands (sine1 etc.)
*/
public class Buffer
implements Constants
{
private final Server server;
private final int bufNum;
private int numFrames;
private int numChannels;
private double sampleRate;
private String path = null;
private CompletionAction doOnInfo = null;
// public Buffer( Server server, int numFrames )
// {
// this( server, numFrames, 1 );
// }
/**
* Creates a new Buffer with given number of frames and channels.
* This method uses the Server's allocators but does not send
* an <code>allocMsg</code> to the server.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
*
* @see #alloc()
*
* @warning when the allocators are exhausted, the <code>bufNum</code> of the
* returned <code>Buffer</code> instance is <code>-1</code>. The caller
* is responsible for dealing with this possible failure.
*/
public Buffer( Server server, int numFrames, int numChannels )
{
this( server, numFrames, numChannels, server.getBufferAllocator().alloc( 1 ));
}
/**
* Creates a new Buffer with given number of frames and channels.
* This method requires an explicit buffer index and does not use the Server's allocators.
* This method does not send
* an <code>allocMsg</code> to the server.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @param bufNum the index of the buffer
*/
public Buffer( Server server, int numFrames, int numChannels, int bufNum )
{
this.server = server;
this.bufNum = bufNum;
this.numFrames = numFrames;
this.numChannels = numChannels;
this.sampleRate = server.getSampleRate();
}
private Buffer( Server server, int bufNum )
{
this.server = server;
this.bufNum = bufNum;
}
/**
* Queries the server at which the buffer resides
*
* @return the buffer's <code>Server</code>
*/
public Server getServer()
{
return server;
}
/**
* Queries the buffer data's sample rate. This rate is
* updated when an asynchronous read command is completed
* and buffer info has been received from the server.
*
* @return the buffer content's sample rate
*/
public double getSampleRate()
{
return sampleRate;
}
protected void setSampleRate( double sampleRate )
{
this.sampleRate = sampleRate;
}
/**
* Queries the buffer's index.
*
* @return the buffer index
*/
public int getBufNum()
{
return bufNum;
}
/**
* Queries the buffer data's number of frames (samples per channel).
* In ansynchronous allocation by read this value is filled in when
* the read is completed
* and buffer info has been received from the server.
*
* @return the number of frames in the buffer
*/
public int getNumFrames()
{
return numFrames;
}
protected void setNumFrames( int numFrames )
{
this.numFrames = numFrames;
}
/**
* Queries the buffer's number of channels.
* In ansynchronous allocation by read this value is filled in when
* the read is completed
* and buffer info has been received from the server.
*
* @return the number of channels in the buffer
*/
public int getNumChannels()
{
return numChannels;
}
protected void setNumChannels( int numChannels )
{
this.numChannels = numChannels;
}
/**
* Queries the buffer's sound file path.
* In ansynchronous allocation by read this value is instantely filled in.
*
* @return the sound file path of the buffer or <code>null</code>
*/
public String getPath()
{
return path;
}
private void setPath( String path )
{
this.path = path;
}
/**
* Queries the buffer's duration in seconds.
* This is only valid after the buffer info (such as sampleRate)
* has been retrieved.
*
* @return the total duration of the buffer (when played back at normal rate) in seconds
*/
public double getDuration()
{
return getNumFrames() / getSampleRate();
}
public String toString()
{
return( "Buffer(" + getBufNum() + ", " + getNumFrames() + ", " + getNumChannels() + ", " + getSampleRate() + ", " + getPath() + ")" );
}
/**
* Allocates and returns a new mono Buffer with given number of frames.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer alloc( Server server, int numFrames )
throws IOException
{
return Buffer.alloc( server, numFrames, 1 );
}
/**
* Allocates and returns a new Buffer with given number of channels and frames.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer alloc( Server server, int numFrames, int numChannels )
throws IOException
{
return Buffer.alloc( server, numFrames, numChannels, null );
}
/**
* Allocates and returns a new Buffer with given number of channels and frames.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @param completionFunc a function that returns an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer alloc( Server server, int numFrames, int numChannels, CompletionFunction completionFunc )
throws IOException
{
final int bufNum = server.getBufferAllocator().alloc( 1 );
if( bufNum == -1 ) {
Server.getPrintStream().println(
"Buffer.alloc: failed to get a buffer allocated. " +
"; server: " + server.getName() );
return null;
} else {
return Buffer.alloc( server, numFrames, numChannels, completionFunc, bufNum );
}
}
/**
* Allocates and returns a new Buffer with given number of channels and frames.
* This uses an explicitly provided buffer index and not the server's allocator.
*
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @param completionFunc a function that returns an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @param bufNum the index by which the buffer is known on the server
* @return the newly created Buffer
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer alloc( Server server, int numFrames, int numChannels, CompletionFunction completionFunc, int bufNum )
throws IOException
{
final Buffer buf = new Buffer( server, numFrames, numChannels, bufNum ); // sets sample rate
buf.alloc( completionFunc == null ? null : completionFunc.completion( buf ));
return buf;
}
/**
* Allocates and returns an array of neighbouring single channel <code>Buffer</code> objects
* with given number of frames. Neighbouring means, that
* <code>buf[ n ].getBufNum() == buf[ n-1 ].getBufNum() + 1</code>.
*
* @param numBufs the number of buffers to allocate
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @return the newly created Buffers
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer[] allocConsecutive( int numBufs, Server server, int numFrames )
throws IOException
{
return Buffer.allocConsecutive( numBufs, server, numFrames, 1 );
}
/**
* Allocates and returns an array of neighbouring <code>Buffer</code> objects with given number
* of channels and frames. Neighbouring means, that
* <code>buf[ n ].getBufNum() == buf[ n-1 ].getBufNum() + 1</code>.
*
* @param numBufs the number of buffers to allocate
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @return the newly created Buffers
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer[] allocConsecutive( int numBufs, Server server, int numFrames, int numChannels )
throws IOException
{
return Buffer.allocConsecutive( numBufs, server, numFrames, numChannels, null );
}
/**
* Allocates and returns an array of neighbouring <code>Buffer</code> objects with given number
* of channels and frames. Neighbouring means, that
* <code>buf[ n ].getBufNum() == buf[ n-1 ].getBufNum() + 1</code>.
*
* @param numBufs the number of buffers to allocate
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @param completionFunc a function that returns an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @return the newly created Buffers
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer[] allocConsecutive( int numBufs, Server server, int numFrames, int numChannels, CompletionFunction completionFunc )
throws IOException
{
final int bufNum = server.getBufferAllocator().alloc( numBufs );
if( bufNum == -1 ) {
Server.getPrintStream().println(
"Buffer.alloc: failed to get " + numBufs + " buffers allocated. " +
"; server: " + server.getName() );
return null;
} else {
return Buffer.allocConsecutive( numBufs, server, numFrames, numChannels, completionFunc, bufNum );
}
}
/**
* Allocates and returns an array of neighbouring <code>Buffer</code> objects with given number
* of channels and frames. This uses an explicitly provided buffer index and not the server's
* allocator. The first element of the returned array has a buffer index equal to the provided
* <code>bufNum</code>, the next element has a buffer index of <code>bufNum + 1</code>,
* the next element an index of <code>bufNum + 2</code> etc.
*
* @param numBufs the number of buffers to allocate
* @param server the server to which the buffer belongs
* @param numFrames the number of frames (samples per channel) that buffer occupies
* @param numChannels the number of channels the buffer occupies
* @param completionFunc a function that returns an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @param bufNum the index by which the first buffer is known on the server.
* the consecutive buffers have indices of <code>bufNum + (1...numBufs-1)</code>
* @return the newly created Buffers
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer[] allocConsecutive( int numBufs, Server server, int numFrames, int numChannels, CompletionFunction completionFunc, int bufNum )
throws IOException
{
final Buffer[] bufs = new Buffer[ numBufs ];
Buffer buf;
boolean success = false;
try {
for( int i = 0; i < numBufs; i++ ) {
buf = new Buffer( server, numFrames, numChannels, bufNum + i );
buf.alloc( completionFunc == null ? null : completionFunc.completion( buf ));
bufs[ i ] = buf;
}
success = true;
return bufs;
}
finally {
if( !success ) {
for( int i = 0; i < numBufs; i++ ) {
if( bufs[ i ] != null ) {
try {
bufs[ i ].free();
} catch( IOException e1 ) { /* ignored */ }
}
}
}
}
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*/
public void alloc()
throws IOException
{
alloc( null );
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor.
*
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation is complete. can be <code>null</code>.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*/
public void alloc( OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( allocMsg( completionMsg ));
}
/**
* Creates an OSC <code>/b_alloc</code> message to allocate the buffer created with the basic <code>new</code> constructor.
*
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*/
public OSCMessage allocMsg()
throws IOException
{
return allocMsg( null );
}
/**
* Creates an OSC <code>/b_alloc</code> message to allocate the buffer created with the basic <code>new</code> constructor.
*
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation is complete. can be <code>null</code>.
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*/
public OSCMessage allocMsg( OSCMessage completionMsg )
throws IOException
{
addToServerArray();
final Object[] args = completionMsg == null ?
new Object[] {
new Integer( getBufNum() ), new Integer( getNumFrames() ), new Integer( getNumChannels() )}
: new Object[] {
new Integer( getBufNum() ), new Integer( getNumFrames() ), new Integer( getNumChannels() ),
completionMsg };
return( new OSCMessage( "/b_alloc", args ));
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*/
public void allocRead( String path )
throws IOException
{
allocRead( path, 0 );
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void allocRead( String path, long startFrame )
throws IOException
{
allocRead( path, startFrame, -1 );
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void allocRead( String path, long startFrame, int numFrames )
throws IOException
{
allocRead( path, startFrame, numFrames, null );
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation and reading is complete. can be <code>null</code>.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void allocRead( String path, long startFrame, int numFrames, OSCMessage completionMsg )
throws IOException
{
// setPath() is called by allocReadMsg()
// setPath( path );
getServer().sendMsg( allocReadMsg( path, startFrame, numFrames, completionMsg ));
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in selected channels of a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void allocReadChannel( String path, long startFrame, int numFrames, int[] channels )
throws IOException
{
allocReadChannel( path, startFrame, numFrames, channels, null );
}
/**
* Allocates the buffer created with the basic <code>new</code> constructor,
* by reading in selected channels of a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation and reading is complete. can be <code>null</code>.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void allocReadChannel( String path, long startFrame, int numFrames, int[] channels, OSCMessage completionMsg )
throws IOException
{
// setPath() is called by allocReadChannelMsg()
// setPath( path );
getServer().sendMsg( allocReadChannelMsg( path, startFrame, numFrames, channels, completionMsg ));
}
/**
* Creates an OSC <code>/b_allocRead</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*/
public OSCMessage allocReadMsg( String path )
throws IOException
{
return allocReadMsg( path, 0 );
}
/**
* Creates an OSC <code>/b_allocRead</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage allocReadMsg( String path, long startFrame )
throws IOException
{
return allocReadMsg( path, startFrame, -1 );
}
/**
* Creates an OSC <code>/b_allocRead</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage allocReadMsg( String path, long startFrame, int numFrames )
throws IOException
{
return allocReadMsg( path, startFrame, numFrames, null );
}
/**
* Creates an OSC <code>/b_allocRead</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation and reading is complete. can be <code>null</code>.
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage allocReadMsg( String path, long startFrame, int numFrames, OSCMessage completionMsg )
throws IOException
{
addToServerArray();
if( startFrame > 0x7FFFFFFFL ) {
Server.getPrintStream().println(
"Buffer.allocReadMsg : startFrame (" + startFrame + ") exceeds 32bit int" );
}
setPath( path );
final Object[] args = completionMsg == null ?
new Object[] {
new Integer( getBufNum() ), path, new Long( startFrame ), new Integer( numFrames )}
: new Object[] {
new Integer( getBufNum() ), path, new Long( startFrame ), new Integer( numFrames ),
completionMsg };
return( new OSCMessage( "/b_allocRead", args ));
}
/**
* Creates an OSC <code>/b_allocReadChannel</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in selected channels from a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage allocReadChannelMsg( String path, long startFrame, int numFrames, int[] channels )
throws IOException
{
return allocReadChannelMsg( path, startFrame, numFrames, channels, null );
}
/**
* Creates an OSC <code>/b_allocReadChannel</code> message to allocate the buffer created with the basic <code>new</code> constructor,
* by reading in selected channels from a sound file.
*
* @param path the path to the sound file
* @param startFrame starting frame in the sound file
* @param numFrames the number of frames to read, which equals the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the allocation and reading is complete. can be <code>null</code>.
* @return the message to be sent to the server
*
* @see #Buffer( Server, int, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage allocReadChannelMsg( String path, long startFrame, int numFrames, int[] channels, OSCMessage completionMsg )
throws IOException
{
addToServerArray();
if( startFrame > 0x7FFFFFFFL ) {
Server.getPrintStream().println(
"Buffer.allocReadChannelMsg : startFrame (" + startFrame + ") exceeds 32bit int" );
}
setPath( path );
final Object[] args = new Object[ 4 + channels.length + (completionMsg == null ? 0 : 1) ];
args[ 0 ] = new Integer( getBufNum() );
args[ 1 ] = path;
args[ 2 ] = new Long( startFrame );
args[ 3 ] = new Integer( numFrames );
for( int i = 4, j = 0; j < channels.length; ) {
args[ i++ ] = new Integer( channels[ j++ ]);
}
if( completionMsg != null ) args[ args.length - 1 ] = completionMsg;
return( new OSCMessage( "/b_allocReadChannel", args ));
}
/**
* Reads a whole file into memory for PlayBuf etc.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*/
public static Buffer read( Server server, String path )
throws IOException
{
return Buffer.read( server, path, 0 );
}
/**
* Reads a whole file into memory for PlayBuf etc., starting at a given frame.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer read( Server server, String path, long startFrame )
throws IOException
{
return Buffer.read( server, path, startFrame, -1 );
}
/**
* Reads a section of a file into memory for PlayBuf etc.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer read( Server server, String path, long startFrame, int numFrames )
throws IOException
{
return Buffer.read( server, path, startFrame, numFrames, null );
}
/**
* Reads a section of a file into memory for PlayBuf etc.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param action an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer read( Server server, String path, long startFrame, int numFrames, CompletionAction action )
throws IOException
{
final int bufNum = server.getBufferAllocator().alloc( 1 );
if( bufNum == -1 ) {
Server.getPrintStream().println(
"Buffer.read: failed to get a buffer allocated. " +
"; server: " + server.getName() );
return null;
} else {
return Buffer.read( server, path, startFrame, numFrames, action, bufNum );
}
}
/**
* Reads a section of a file into memory for PlayBuf etc.
* adds a query as a completion message. An explicit buffer index is provided.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param action an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
* @param bufNum the index to use for the buffer
*
* @return the newly created buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer read( Server server, String path, long startFrame, int numFrames, CompletionAction action, int bufNum )
throws IOException
{
final Buffer buf = new Buffer( server, bufNum );
buf.setDoOnInfo( action );
buf.waitForBufInfo();
buf.allocRead( path, startFrame, numFrames, buf.queryMsg() );
return buf;
}
/**
* Reads a section of a given set of channels from a file into memory for PlayBuf etc.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer. Use <code>-1</code> to read the whole file.
* @param channels an array of channel indices to read (starting from <code>0</code>)
*
* @return the newly created buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readChannel( Server server, String path, long startFrame, int numFrames, int[] channels )
throws IOException
{
return Buffer.readChannel( server, path, startFrame, numFrames, channels, null );
}
/**
* Reads a section of a given set of channels from a file into memory for PlayBuf etc.
* adds a query as a completion message.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param action an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
*
* @return the newly created buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readChannel( Server server, String path, long startFrame, int numFrames, int[] channels, CompletionAction action )
throws IOException
{
final int bufNum = server.getBufferAllocator().alloc( 1 );
if( bufNum == -1 ) {
Server.getPrintStream().println(
"Buffer.readChannel: failed to get a buffer allocated. " +
"; server: " + server.getName() );
return null;
} else {
return Buffer.readChannel( server, path, startFrame, numFrames, channels, action, bufNum );
}
}
/**
* Reads a section of a given set of channels from a file into memory for PlayBuf etc.
* adds a query as a completion message. An explicit buffer index is provided.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param action an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
* @param bufNum the index to use for the buffer
*
* @return the newly created buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readChannel( Server server, String path, long startFrame, int numFrames, int[] channels, CompletionAction action, int bufNum )
throws IOException
{
final Buffer buf = new Buffer( server, bufNum );
buf.setDoOnInfo( action );
buf.waitForBufInfo();
buf.allocReadChannel( path, startFrame, numFrames, channels, buf.queryMsg() );
return buf;
}
/**
* Reads in as many frames from a sound file as fit into the buffer,
* starting at the beginning of the file.
* Closes the file after reading.
*
* @param path the path to the sound file
*
* @throws IOException if an error occurs while sending the OSC message
*/
public void read( String path )
throws IOException
{
read( path, 0 );
}
/**
* Reads in as many frames from a sound file as fit into the buffer,
* starting at a given frame in the file.
* Closes the file after reading.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void read( String path, long fileStartFrame )
throws IOException
{
read( path, fileStartFrame, -1 );
}
/**
* Reads in frames from a sound file into the buffer.
* Closes the file after reading.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void read( String path, long fileStartFrame, int numFrames )
throws IOException
{
read( path, fileStartFrame, numFrames, 0 );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer. Closes the file after reading.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void read( String path, long fileStartFrame, int numFrames, int bufStartFrame )
throws IOException
{
read( path, fileStartFrame, numFrames, bufStartFrame, false );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void read( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen )
throws IOException
{
read( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, null );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param action an action to be executed when the <code>/b_info</code> comes back from the server.
* at this moment, the read operation is completed.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void read( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, CompletionAction action )
throws IOException
{
addToServerArray();
setDoOnInfo( action );
waitForBufInfo();
getServer().sendMsg( readMsg( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, queryMsg() ));
}
/**
* Reads in frames from selected channels of a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param action an action to be executed when the <code>/b_info</code> comes back from the server.
* at this moment, the read operation is completed.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readChannel( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, int[] channels, CompletionAction action )
throws IOException
{
addToServerArray();
setDoOnInfo( action );
waitForBufInfo();
getServer().sendMsg( readChannelMsg( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, channels, queryMsg() ));
}
/**
* Creates an OSC <code>/b_read</code> message to read in as many frames from a sound file as fit into the buffer,
* starting at the beginning of the file,
* closing the file after reading.
*
* @param path the path to the sound file
* @return the message to be sent to the server
*/
public OSCMessage readMsg( String path )
{
return readMsg( path, 0 );
}
/**
* Creates an OSC <code>/b_read</code> message to read in as many frames from a sound file as fit into the buffer,
* starting at a given frame in the file,
* closing the file after reading.
*
* @param path the path to the sound file
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readMsg( String path, long fileStartFrame )
{
return readMsg( path, fileStartFrame, -1 );
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from a sound file into the buffer,
* closing the file after reading.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readMsg( String path, long fileStartFrame, int numFrames )
{
return readMsg( path, fileStartFrame, numFrames, 0 );
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from a sound file into the buffer, beginning a
* given offset in the buffer, closing the file after reading.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readMsg( String path, long fileStartFrame, int numFrames, int bufStartFrame )
{
return readMsg( path, fileStartFrame, numFrames, bufStartFrame, false );
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readMsg( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen )
{
return readMsg( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, null );
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readMsg( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, OSCMessage completionMsg )
{
if( fileStartFrame > 0x7FFFFFFFL ) {
Server.getPrintStream().println(
"Buffer.readMsg : fileStartFrame (" + fileStartFrame + ") exceeds 32bit int" );
}
setPath( path );
final Object[] args = completionMsg == null ?
new Object[] {
new Integer( getBufNum() ), path, new Long( fileStartFrame ), new Integer( numFrames ),
new Integer( bufStartFrame ), new Integer( leaveOpen ? 1 : 0 )}
: new Object[] {
new Integer( getBufNum() ), path, new Long( fileStartFrame ), new Integer( numFrames ),
new Integer( bufStartFrame ), new Integer( leaveOpen ? 1 : 0 ),
completionMsg };
return( new OSCMessage( "/b_read", args ));
// doesn't set my numChannels etc.
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from selected channels of
* a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readChannelMsg( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, int[] channels )
{
return readChannelMsg( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, channels, null );
}
/**
* Creates an OSC <code>/b_read</code> message to read in frames from selected channels of
* a sound file into the buffer, beginning a
* given offset in the buffer.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param channels an array of channel indices to read (starting from <code>0</code>)
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
* @return the message to be sent to the server
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public OSCMessage readChannelMsg( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, int[] channels, OSCMessage completionMsg )
{
if( fileStartFrame > 0x7FFFFFFFL ) {
Server.getPrintStream().println(
"Buffer.readChannelMsg : fileStartFrame (" + fileStartFrame + ") exceeds 32bit int" );
}
setPath( path );
final Object[] args = new Object[ 6 + channels.length + (completionMsg == null ? 0 : 1) ];
args[ 0 ] = new Integer( getBufNum() );
args[ 1 ] = path;
args[ 2 ] = new Long( fileStartFrame );
args[ 3 ] = new Integer( numFrames );
args[ 4 ] = new Integer( bufStartFrame );
args[ 5 ] = new Integer( leaveOpen ? 1 : 0 );
for( int i = 6, j = 0; j < channels.length; ) {
args[ i++ ] = new Integer( channels[ j++ ]);
}
if( completionMsg != null ) args[ args.length - 1 ] = completionMsg;
return( new OSCMessage( "/b_readChannel", args ));
// doesn't set my numChannels etc.
}
/**
* Writes the buffer contents to a sound file, using AIFF integer 24 bit format.
*
* @param path the path name of the file to write to
*
* @throws IOException if an error occurs while sending the OSC message
*/
public void write( String path )
throws IOException
{
write( path, "aiff", "int24" );
}
/**
* Writes the buffer contents to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public void write( String path, String headerFormat, String sampleFormat )
throws IOException
{
write( path, headerFormat, sampleFormat, -1 );
}
/**
* Writes the buffer contents to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public void write( String path, String headerFormat, String sampleFormat, int numFrames )
throws IOException
{
write( path, headerFormat, sampleFormat, numFrames, 0 );
}
/**
* Writes a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public void write( String path, String headerFormat, String sampleFormat, int numFrames, int bufStartFrame )
throws IOException
{
write( path, headerFormat, sampleFormat, numFrames, bufStartFrame, false );
}
/**
* Writes a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
* @param leaveOpen <code>false</code> to close the sound file after writing, <code>true</code> to
* leave it open (as required for a <code>DiskOut</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public void write( String path, String headerFormat, String sampleFormat, int numFrames, int bufStartFrame, boolean leaveOpen )
throws IOException
{
write( path, headerFormat, sampleFormat, numFrames, bufStartFrame, leaveOpen, null );
}
/**
* Writes a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
* @param leaveOpen <code>false</code> to close the sound file after writing, <code>true</code> to
* leave it open (as required for a <code>DiskOut</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the writing is complete. can be <code>null</code>.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public void write( String path, String headerFormat, String sampleFormat, int numFrames, int bufStartFrame,
boolean leaveOpen, OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( writeMsg( path, headerFormat, sampleFormat, numFrames, bufStartFrame, leaveOpen, completionMsg ));
}
/**
* Creates an OSC <code>/b_write</code> message to write the buffer contents to a sound file, using AIFF integer 24 bit format.
*
* @param path the path name of the file to write to
* @return the message to send to the server
*/
public OSCMessage writeMsg( String path )
{
return writeMsg( path, "aiff", "int24" );
}
/**
* Creates an OSC <code>/b_write</code> message to write the buffer contents to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @return the message to send to the server
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public OSCMessage writeMsg( String path, String headerFormat, String sampleFormat )
{
return writeMsg( path, headerFormat, sampleFormat, -1 );
}
/**
* Creates an OSC <code>/b_write</code> message to write the buffer contents to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @return the message to send to the server
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public OSCMessage writeMsg( String path, String headerFormat, String sampleFormat, int numFrames )
{
return writeMsg( path, headerFormat, sampleFormat, numFrames, 0 );
}
/**
* Creates an OSC <code>/b_write</code> message to write a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
* @return the message to send to the server
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public OSCMessage writeMsg( String path, String headerFormat, String sampleFormat, int numFrames, int bufStartFrame )
{
return writeMsg( path, headerFormat, sampleFormat, numFrames, bufStartFrame, false );
}
/**
* Creates an OSC <code>/b_write</code> message to write a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
* @param leaveOpen <code>false</code> to close the sound file after writing, <code>true</code> to
* leave it open (as required for a <code>DiskOut</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @return the message to send to the server
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public OSCMessage writeMsg( String path, String headerFormat, String sampleFormat, int numFrames, int bufStartFrame, boolean leaveOpen )
{
return writeMsg( path, headerFormat, sampleFormat, numFrames, bufStartFrame, leaveOpen, null );
}
/**
* Creates an OSC <code>/b_write</code> message to write a section of the buffer to a sound file.
*
* @param path the path name of the file to write to
* @param headerFormat one of <code>kHeaderAIFF</code> etc.
* @param sampleFormat one of <code>kSampleInt24</code> etc.
* @param numFrames to number of frames to write, or <code>-1</code> to write the whole buffer
* @param bufStartFrame the start frame in the buffer from which to write
* @param leaveOpen <code>false</code> to close the sound file after writing, <code>true</code> to
* leave it open (as required for a <code>DiskOut</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the writing is complete. can be <code>null</code>.
* @return the message to send to the server
*
* @see Constants#kHeaderAIFF
* @see Constants#kSampleInt24
*/
public OSCMessage writeMsg( String path, String headerFormat, String sampleFormat, int numFrames,
int bufStartFrame, boolean leaveOpen, OSCMessage completionMsg )
{
final Object[] args = completionMsg == null ?
new Object[] {
new Integer( getBufNum() ), path, headerFormat, sampleFormat, new Integer( numFrames ),
new Integer( bufStartFrame ), new Integer( leaveOpen ? 1 : 0 )}
: new Object[] {
new Integer( getBufNum() ), path, headerFormat, sampleFormat, new Integer( numFrames ),
new Integer( bufStartFrame ), new Integer( leaveOpen ? 1 : 0 ), completionMsg };
return( new OSCMessage( "/b_write", args ));
}
private void setDoOnInfo( CompletionAction action )
{
doOnInfo = action;
}
private CompletionAction getDoOnInfo()
{
return doOnInfo;
}
/**
* Reads a whole file into memory for PlayBuf etc. Just like <code>read( Server, String )</code> but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #read( Server, String )
*/
public static Buffer readNoUpdate( Server server, String path )
throws IOException
{
return Buffer.readNoUpdate( server, path, 0 );
}
/**
* Reads a whole file into memory for PlayBuf etc. Just like <code>read( Server, String, long )</code> but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #read( Server, String, long )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readNoUpdate( Server server, String path, long startFrame )
throws IOException
{
return Buffer.readNoUpdate( server, path, startFrame, -1 );
}
/**
* Reads a section of a file into memory for PlayBuf etc. Just like <code>read( Server, String, long, int )</code> but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #read( Server, String, long, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readNoUpdate( Server server, String path, long startFrame, int numFrames )
throws IOException
{
return Buffer.readNoUpdate( server, path, startFrame, numFrames, null );
}
/**
* Reads a section of a file into memory for PlayBuf etc. Just like <code>read( Server, String, long, int, CompletionFunction )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param completionFunc an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
*
* @return the newly created Buffer or <code>null</code> if the server's buffer allocator
* is exhausted
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #read( Server, String, long, int, CompletionAction )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readNoUpdate( Server server, String path, long startFrame, int numFrames, CompletionFunction completionFunc )
throws IOException
{
final int bufNum = server.getBufferAllocator().alloc( 1 );
if( bufNum == -1 ) {
Server.getPrintStream().println(
"Buffer.readNoUpdate: failed to get a buffer allocated. " +
"; server: " + server.getName() );
return null;
} else {
return Buffer.readNoUpdate( server, path, startFrame, numFrames, completionFunc, bufNum );
}
}
/**
* Reads a section of a file into memory for PlayBuf etc. Just like <code>read( Server, String, long, int, CompletionFunction, int )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
* An explicit buffer index is provided.
*
* @param server the server on which the buffer is allocated
* @param path the path to the sound file
* @param startFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read. this is equal to the number of frames
* allocated for the buffer
* @param completionFunc an action to be executed when the <code>/b_info</code> message comes
* back from the server. at this time the buffer has been allocated and filled.
* <code>action</code> can be <code>null</code>
* @param bufNum the index to use for the buffer
*
* @return the newly created buffer
*
* @throws IOException if an error occurs while sending the OSC message
*
* @see #read( Server, String, long, int, CompletionAction, int )
*
* @warning <code>long startFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public static Buffer readNoUpdate( Server server, String path, long startFrame, int numFrames, CompletionFunction completionFunc, int bufNum )
throws IOException
{
final Buffer buf = new Buffer( server, bufNum );
buf.allocRead( path, startFrame, numFrames, completionFunc == null ? null : completionFunc.completion( buf ));
return buf;
}
/**
* Reads in as many frames from a sound file as fit into the buffer,
* starting at the beginning of the file.
* Closes the file after reading. Just like <code>read( String )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
*
* @throws IOException if an error occurs while sending the OSC message
*/
public void readNoUpdate( String path )
throws IOException
{
readNoUpdate( path, 0 );
}
/**
* Reads in as many frames from a sound file as fit into the buffer,
* starting at a given frame in the file.
* Closes the file after reading. Just like <code>read( String, long )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readNoUpdate( String path, long fileStartFrame )
throws IOException
{
readNoUpdate( path, fileStartFrame, -1 );
}
/**
* Reads in frames from a sound file into the buffer.
* Closes the file after reading. Just like <code>read( String, long, int )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readNoUpdate( String path, long fileStartFrame, int numFrames )
throws IOException
{
readNoUpdate( path, fileStartFrame, numFrames, 0 );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer. Closes the file after reading. Just like <code>read( String, long, int, int )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readNoUpdate( String path, long fileStartFrame, int numFrames, int bufStartFrame )
throws IOException
{
readNoUpdate( path, fileStartFrame, numFrames, bufStartFrame, false );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer. Just like <code>read( String, long, int, int, boolean )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readNoUpdate( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen )
throws IOException
{
readNoUpdate( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, null );
}
/**
* Reads in frames from a sound file into the buffer, beginning a
* given offset in the buffer. Just like <code>read( String, long, int, int, boolean, CompletionAction )</code>
* but without sending
* a <code>/b_query</code>. Hence, the internal fields are not updated
* unless you explicitly call <code>query()</code>.
*
* @param path the path to the sound file
* @param fileStartFrame the frame index in the sound file to start reading from
* @param numFrames the number of frames to read
* a value of <code>-1</code> indicates that as many frames as fit into the buffer
* should be read
* @param bufStartFrame the offset (in frames) in the buffer at which the filling begins
* @param leaveOpen <code>false</code> to close the sound file after reading, <code>true</code> to
* leave it open (as required for a <code>DiskIn</code> UGen). If you leave the file
* open, don't forget to call <code>close</code> on the buffer eventually.
* @param completionMsg an <code>OSCMessage</code> which is processed by the server
* when the reading is complete. can be <code>null</code>.
*
* @throws IOException if an error occurs while sending the OSC message
*
* @warning <code>long fileStartFrame</code> is truncated to 32bit by <code>OSCMessage</code> for now
*/
public void readNoUpdate( String path, long fileStartFrame, int numFrames, int bufStartFrame, boolean leaveOpen, OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( readMsg( path, fileStartFrame, numFrames, bufStartFrame, leaveOpen, completionMsg ));
}
/**
* @warning numChannels defaults to 1 (not 2 as in sclang) !!
*/
public static Buffer cueSoundFile( Server server, String path )
throws IOException
{
return Buffer.cueSoundFile( server, path, 0 );
}
/**
* @warning numChannels defaults to 1 (not 2 as in sclang) !!
*/
public static Buffer cueSoundFile( Server server, String path, long startFrame )
throws IOException
{
return Buffer.cueSoundFile( server, path, startFrame, 1 );
}
public static Buffer cueSoundFile( Server server, String path, long startFrame, int numChannels )
throws IOException
{
return Buffer.cueSoundFile( server, path, startFrame, numChannels, 32768 );
}
public static Buffer cueSoundFile( Server server, String path, long startFrame, int numChannels, int bufferSize )
throws IOException
{
return Buffer.cueSoundFile( server, path, startFrame, numChannels, bufferSize, null );
}
// preload a buffer for use with DiskIn
public static Buffer cueSoundFile( Server server, final String path, final long startFrame, int numChannels,
final int bufferSize, final CompletionFunction completionFunc )
throws IOException
{
final Buffer buf = Buffer.alloc( server, bufferSize, numChannels, new CompletionFunction() {
public OSCMessage completion( Buffer buf )
{
return buf.readMsg( path, startFrame, bufferSize, 0, true, completionFunc == null ? null : completionFunc.completion( buf ));
}
});
buf.addToServerArray();
return buf;
}
public void cueSoundFile( String path )
throws IOException
{
cueSoundFile( path, 0 );
}
public void cueSoundFile( String path, long startFrame )
throws IOException
{
cueSoundFile( path, startFrame, null );
}
public void cueSoundFile( String path, long startFrame, OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( cueSoundFileMsg( path, startFrame, completionMsg ));
}
public OSCMessage cueSoundFileMsg( String path, long startFrame, OSCMessage completionMsg )
{
return readMsg( path, startFrame, getNumFrames(), 0, true, completionMsg );
}
// cache Buffers in an Array for easy info updating
private void addToServerArray()
throws IOException
{
getServer().addBuf( this );
}
// tell the server to wait for a b_info
private void waitForBufInfo()
throws IOException
{
getServer().waitForBufInfo();
}
/**
* Called from Server when b_info is received.
* Do not call this method directly
*/
protected void queryDone()
{
if( getDoOnInfo() != null ) {
getDoOnInfo().completion( this );
setDoOnInfo( null );
}
}
public void fill( int startAt, int numSamples, float value )
throws IOException
{
getServer().sendMsg( fillMsg( startAt, numSamples, value ));
}
public OSCMessage fillMsg( int startAt, int numSamples, float value )
{
return( new OSCMessage( "/b_fill", new Object[] {
new Integer( getBufNum() ), new Integer( startAt ), new Integer( numSamples ), new Float( value )}));
}
public void fill( int[] startAt, int[] numSamples, float[] value )
throws IOException
{
getServer().sendMsg( fillMsg( startAt, numSamples, value ));
}
public OSCMessage fillMsg( int[] startAt, int[] numSamples, float[] value )
{
final Object[] args = new Object[ startAt.length * 3 + 1 ];
args[ 0 ] = new Integer( getBufNum() );
for( int i = 0, j = 1; i < startAt.length; i++ ) {
args[ j++ ] = new Integer( startAt[ i ]);
args[ j++ ] = new Integer( numSamples[ i ]);
args[ j++ ] = new Float( value[ i ]);
}
return( new OSCMessage( "/b_fill", args ));
}
// close a file, write header, after DiskOut usage
public void close()
throws IOException
{
close( null );
}
public void close( OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( closeMsg( completionMsg ));
}
public OSCMessage closeMsg()
{
return closeMsg( null );
}
public OSCMessage closeMsg( OSCMessage completionMsg )
{
return simpleMsg( "/b_close", completionMsg );
}
private OSCMessage simpleMsg( String cmdName, OSCMessage completionMsg )
{
final Object[] args = completionMsg == null ?
new Object[] { new Integer( getBufNum() )}
: new Object[] { new Integer( getBufNum() ), completionMsg };
return( new OSCMessage( cmdName, args ));
}
public void free()
throws IOException
{
free( null );
}
public void free( OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( freeMsg( completionMsg ));
}
public OSCMessage freeMsg()
{
return freeMsg( null );
}
public OSCMessage freeMsg( OSCMessage completionMsg )
{
getServer().freeBuf( getBufNum() );
getServer().getBufferAllocator().free( getBufNum() );
return simpleMsg( "/b_free", completionMsg );
}
public void zero()
throws IOException
{
zero( null );
}
public void zero( OSCMessage completionMsg )
throws IOException
{
getServer().sendMsg( zeroMsg( completionMsg ));
}
public OSCMessage zeroMsg()
{
return zeroMsg( null );
}
public OSCMessage zeroMsg( OSCMessage completionMsg )
{
return simpleMsg( "/b_zero", completionMsg );
}
/**
* Frees all known buffers on a server.
* Known buffers are those which were allocated regularly
* using the server's buffer allocator.
*
* @param server the server whose buffers should be freed
*
* @throws IOException if an error occurs in OSC bundle sending
*/
public static void freeAll( Server server )
throws IOException
{
final BlockAllocator bufferAllocator = server.getBufferAllocator();
final java.util.List blocks = bufferAllocator.getAllocatedBlocks();
BlockAllocator.Block block;
final OSCBundle bndl = new OSCBundle( 0.0 );
for( int i = 0; i < blocks.size(); i++ ) {
block = (BlockAllocator.Block) blocks.get( i );
bndl.addPacket( new OSCMessage( "/b_free", new Object[] { new Integer( block.getAddress() )}));
bufferAllocator.free( block.getAddress() );
server.freeBuf( block.getAddress() ); // this was forgotten in sclang
}
if( bndl.getPacketCount() > 0 ) server.sendBundle( bndl );
}
/**
* A debugging method for querying the current buffer parameters
* and printing them into the console. This sends a query message
* to the server and upon reply prints the current buffer parameters
* into the console (as defined by <code>server.setPrintStream()</code>).
*
* @throws IOException if a networking error occurs
*
* @todo this simply waits for the next /b_info message to come in without checking the bufNum
* ; also there is no time out
*/
public void query()
throws IOException
{
new OSCResponderNode( getServer(), "/b_info", new OSCResponderNode.Action() {
public void respond( OSCResponderNode r, OSCMessage msg, long time )
{
if( ((Number) msg.getArg( 0 )).intValue() != getBufNum() ) return;
Server.getPrintStream().println(
"bufNum : " + msg.getArg( 0 ) +
"\nnumFrames : " + msg.getArg( 1 ) +
"\nnumChannels : " + msg.getArg( 2 ) +
"\nsampleRate : " + msg.getArg( 3 ) + "\n" );
r.remove();
}
}).add();
getServer().sendMsg( queryMsg() );
}
/**
* Constructs an OSC message <code>/b_query</code> for querying the
* buffer's parameters.
*
* @return the OSC message, ready to be send to the server
*/
public OSCMessage queryMsg()
{
return simpleMsg( "/b_query", null );
}
/**
* Asynchronously updates the buffer parameters
* (such as number of frames or sample rate). It sends
* a query message to the server and upon reply, executes
* a given completion action.
*
* @param action the action to be executed once the buffer info is updated
*
* @throws IOException if a networking error occurs
*/
public void updateInfo( CompletionAction action )
throws IOException
{
// add to the array here. That way, update will be accurate even if this buf
// has been freed
addToServerArray();
setDoOnInfo( action );
waitForBufInfo();
getServer().sendMsg( queryMsg() );
}
public void printOn( PrintStream stream )
{
stream.print( this.getClass().getName() + "(" + getBufNum() + "," + getNumFrames() + "," +
getNumChannels() + "," + getSampleRate() + "," + getPath() + ")" );
}
/**
* Plays the buffer contents (oneshot) beginning
* on the first audio output.
*
* @return the buffer playing synth. the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play()
throws IOException
{
return play( false );
}
/**
* Plays the buffer contents beginning
* on the first audio output.
*
* @param loop whether the playback should be looped or not.
* @return the buffer playing synth. when not looping, the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play( boolean loop )
throws IOException
{
return play( loop, 1f );
}
/**
* Plays the buffer contents beginning
* on the first audio output.
*
* @param loop whether the playback should be looped or not.
* @param amp the amplitude scaling
* @return the buffer playing synth. when not looping, the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play( boolean loop, float amp )
throws IOException
{
return play( loop, amp, 0 );
}
/**
* Plays the buffer contents.
*
* @param loop whether the playback should be looped or not.
* @param amp the amplitude scaling
* @param outBus the index of the first bus to play on
* @return the buffer playing synth. when not looping, the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play( boolean loop, float amp, int outBus )
throws IOException
{
return play( loop, amp, outBus, 0.02f );
}
/**
* Plays the buffer contents.
*
* @param loop whether the playback should be looped or not.
* @param amp the amplitude scaling
* @param outBus the index of the first bus to play on
* @param fadeTime the time in seconds for the synth to fade in and out (upon release())
* @return the buffer playing synth. when not looping, the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play( boolean loop, float amp, int outBus, float fadeTime )
throws IOException
{
return play( loop, amp, outBus, fadeTime, null, kAddToHead );
}
/**
* Plays the buffer contents.
*
* @param loop whether the playback should be looped or not.
* @param amp the amplitude scaling
* @param outBus the index of the first bus to play on
* @param fadeTime the time in seconds for the synth to fade in and out (upon release())
* @param target to node to add the new synth to
* @param addAction the add action to use when adding the synth
* @return the buffer playing synth. when not looping, the synth is automatically freed
* when the buffer playback is complete.
*
* @throws IOException if an error occurs in message sending
* @warning requires prior UGenInfo.readDefinitions
*/
public Synth play( boolean loop, float amp, int outBus, float fadeTime, Node target, int addAction )
throws IOException
{
final GraphElem bufNum, out, ctrl, dt, gate;
final OSCMessage newMsg;
final String name;
final Synth synth;
final SynthDef def;
GraphElem player, graph;
out = Control.ir( "i_out", 0f );
bufNum = UGen.ir( getBufNum() );
player = UGen.ar( "PlayBuf", getNumChannels(), bufNum, UGen.kr( "BufRateScale", bufNum ), UGen.ir( 1f ), UGen.ir( 0f ), UGen.ir( loop ? 1f : 0f ));
if( fadeTime > 0f ) {
ctrl = Control.kr( new String[] { "fadeTime", "gate" }, new float[] { fadeTime, 1f });
dt = ctrl.getOutput( 0 );
gate = ctrl.getOutput( 1 );
player = UGen.ar( "*", player, UGen.kr( "Linen", gate, dt, UGen.ir( 1f ), dt, UGen.ir( 2f )));
}
graph = UGen.ar( "Out", out, UGen.ar( "*", player, UGen.ir( amp )));
if( !loop ) {
// XXX should be replaced by a Line and BufDur
// graph = UGen.array( graph, UGen.kr( "FreeSelfWhenDone", player ));
graph = UGen.array( graph, UGen.kr( "Line", UGen.ir( 0f ), UGen.ir( 1f ), UGen.kr( "BufDur", bufNum ), UGen.ir( kDoneFree )));
}
name = "temp_" + String.valueOf( Math.abs( hashCode() ));
def = new SynthDef( name, graph );
synth = Synth.basicNew( name, getServer() );
newMsg = synth.newMsg( target, new String[] { "i_out" }, new float[] { outBus }, addAction );
def.send( getServer(), newMsg );
return synth;
}
// ---------- internal classes and interfaces ----------
/**
* Interface describing an action to take place after
* an asynchronous buffer command is completed.
*/
public static interface CompletionAction
{
/**
* Executes the completion action.
*
* @param buf the buffer whose asynchronous action is completed.
*/
public void completion( Buffer buf );
}
/**
* Interface describing an function that creates an
* OSC message used as a completion message in asynchronous buffer commands.
*/
public static interface CompletionFunction
{
/**
* Queries the creation of the completion message.
*
* @param buf the buffer for which the completion message is created
* @return the <code>OSCMessage</code> attached to as completion message to an asynchronous command
*/
public OSCMessage completion( Buffer buf );
}
}