ChucK/Dev/IO
These Wiki pages will be used to coordinate development of the ChucK I/O API specification. The ChucK I/O API will consist of a main IO
class with methods universal to all types of I/O, and three subclasses: FileIO
, NetIO
, and PipeIO
.
Your comments, suggestions, and criticisms are much appreciated. The quality of the I/O API specification should primarily be evaluated on the following three criteria:
- Completeness: you can accomplish any I/O task you might want to perform in ChucK (or at least most of them).
- Elegance: ChucK I/O code is intuitive and easy to write.
- Feasibility: it is not too difficult to actually implement all of the components of this API without interfering with existing ChucK code and conventions.
Contents
ChucK I/O Conventions
Class Hierarchy
Asynchronicity
I/O operations in ChucK are asynchronous by default. Calling an I/O function places the desired I/O operation in a queue, so that I/O does not interfere with real-time audio. This means that after some I/O function has been executed, you cannot be sure at any subsequent line of code that the operation has actually finished unless you do one of the following:
- Call the
finish
function, which waits for all queued I/O operations to finish without advancing time. - Advance time until the I/O queue is cleared, by writing something like
myIO => now;
.
ASCII vs. Binary
TODO: write some details about this.
IO Class
This class cannot be instantiated. In ChucK code, its main purpose is to enable functions to accept and read from any kind of I/O class without regard to the type of I/O that is taking place. This class deliberately includes no "open" methods to start I/O, since this differs greatly depending on whether you are opening a file, a network socket, or a pipe.
Methods
-
fun void close()
- Closes the I/O stream in the appropriate way (close file, close socket, etc.). Automatically calls finish first, to ensure all I/O operations are completed before closing. If you want to allow time to advance while the final I/O operations are being performed, you must write
your_IO_object => now;
before calling close. -
fun void finish()
- Wait for queued I/O operations to finish without advancing time.
-
fun int isIdle()
- Returns true if there are no queued I/O operations, false otherwise.
Reading
-
fun string read(int length)
- Reads up to the specified number of bytes into a string.
-
fun string readLine()
- Reads everything up to and including the next newline character into a string.
-
fun int readInt([int flags])
- Reads in one integer. The flags can optionally be used to specify the bit length of the integer to be read in when in binary mode (default is IO.READ_INT32). The value returned will always be a 32-bit signed ChucK integer, regardless of the number of bits read from the file.
-
fun int readFloat()
- Reads in one float.
-
fun int eof()
- Returns true if end of file has been reached (or the network connection has been closed), or false otherwise.
Writing
-
fun void write(string s)
- Writes out the specified string.
-
fun void writef(string s, ...)
- Writes out the specified string, generated using printf-style conversion specifications.
-
fun void write(int i)
- Writes out the specified int.
-
fun void write(float f)
- Writes out the specified float.
Events
Chucking an IO object to now (for example, as in myIO => now;
) causes time to be advanced until all queued I/O operations for that object have completed.
Operators
The single-ChucK operators can also be used to read from and write to a file in "Pac-Man" fashion.
For example, to write a series of variables to an IO object, you could write:
myIO <- myInt1 <- myInt2 <- myFloat <- myStr;
This would have the same effect as:
myIO.write(myInt1);
myIO.write(myInt2);
myIO.write(myFloat);
myIO.write(myStr);
To read a series of variables from an IO object, you could write:
myIO -> myFloat -> myInt1 -> myStr -> myInt2;
This would have the same effect as:
myIO.readFloat() => myFloat;
myIO.readInt() => myInt1;
myIO.readLine() => myStr;
myIO.readInt() => myInt2;
Constants
-
IO.READ_INT32
IO.READ_INT16
IO.READ_INT8
- These flags can optionally be passed to the
readInt
function when in binary mode to specify the bit length of the integer to be read.
Example
fun void ioexample(IO myIO) {
// Read some integers
int intarray[10];
for (0 => int i; i < intarray.size(); i++)
myIO -> intarray[i]; // same as myIO.readInt() => intarray[i]
// We cannot be sure that intarray is actually filled up until
// we wait for the I/O queue to clear
myIO => now; // allow time to advance while I/O is processing
// Add them up
int sum;
for (0 => int i; i < intarray.size(); i++)
intarray[i] +=> sum;
// Write the result back out
myIO <- sum;
// All finished
myIO.close(); // Automatically calls myIO.finish() first.
}