Beginning of File System integration
This commit is contained in:
917
csound_browser_readme.md
Normal file
917
csound_browser_readme.md
Normal file
@ -0,0 +1,917 @@
|
|||||||
|
# @csound/browser
|
||||||
|
[](https://www.npmjs.com/package/@csound/browser)
|
||||||
|
[](https://github.com/csound/csound/actions?query=workflow%3Acsound_wasm)
|
||||||
|
[](https://github.com/prettier/prettier)
|
||||||
|
|
||||||
|
|
||||||
|
## Api Documentation
|
||||||
|
|
||||||
|
## Objects
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><a href="#CsoundObj">CsoundObj</a> : <code>object</code></dt>
|
||||||
|
<dd><p>CsoundObj API.</p>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><a href="#Csound">Csound([params])</a> ⇒ <code>Promise.<(CsoundObj|undefined)></code></dt>
|
||||||
|
<dd><p>The default entry for @csound/wasm/browser module.
|
||||||
|
If loaded successfully, it returns CsoundObj,
|
||||||
|
otherwise undefined.</p>
|
||||||
|
</dd>
|
||||||
|
<dt><a href="#getTable">getTable(tableNum)</a> ⇒ <code>Promise.<(Float64Array|undefined)></code></dt>
|
||||||
|
<dd></dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
## Typedefs
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><a href="#CSOUND_PARAMS">CSOUND_PARAMS</a></dt>
|
||||||
|
<dd></dd>
|
||||||
|
<dt><a href="#CS_MIDIDEVICE">CS_MIDIDEVICE</a></dt>
|
||||||
|
<dd></dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<a name="CsoundObj"></a>
|
||||||
|
|
||||||
|
## CsoundObj : <code>object</code>
|
||||||
|
CsoundObj API.
|
||||||
|
|
||||||
|
**Kind**: global namespace
|
||||||
|
|
||||||
|
* [CsoundObj](#CsoundObj) : <code>object</code>
|
||||||
|
* _global_
|
||||||
|
* [getTable(tableNum)](#getTable) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
* _static_
|
||||||
|
* [.fs](#CsoundObj.fs) : <code>IFs:memfs</code>
|
||||||
|
* [.eventNames()](#CsoundObj.eventNames) ⇒ <code>Array.<string></code>
|
||||||
|
* [.listenerCount()](#CsoundObj.listenerCount) ⇒ <code>number</code>
|
||||||
|
* [.listeners(eventName)](#CsoundObj.listeners) ⇒ <code>Array.<function()></code>
|
||||||
|
* [.off(eventName, listener)](#CsoundObj.off) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.on(eventName, listener)](#CsoundObj.on) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.addListener(eventName, listener)](#CsoundObj.addListener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.once(eventName, listener)](#CsoundObj.once) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.removeAllListeners(eventName)](#CsoundObj.removeAllListeners) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.removeListener(eventName, listener)](#CsoundObj.removeListener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
* [.getSr()](#CsoundObj.getSr) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getKr()](#CsoundObj.getKr) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getKsmps()](#CsoundObj.getKsmps) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getNchnls()](#CsoundObj.getNchnls) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getNchnlsInput()](#CsoundObj.getNchnlsInput) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.get0dBFS()](#CsoundObj.get0dBFS) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getA4()](#CsoundObj.getA4) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getCurrentTimeSamples()](#CsoundObj.getCurrentTimeSamples) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getSizeOfMYFLT()](#CsoundObj.getSizeOfMYFLT) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.setOption(option)](#CsoundObj.setOption) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.setParams(csoundParams)](#CsoundObj.setParams) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.getParams()](#CsoundObj.getParams) ⇒ [<code>Promise.<CSOUND\_PARAMS></code>](#CSOUND_PARAMS)
|
||||||
|
* [.getDebug()](#CsoundObj.getDebug) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.setDebug(debug)](#CsoundObj.setDebug) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.inputMessage(scoreEvent)](#CsoundObj.inputMessage) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.inputMessageAsync(scoreEvent)](#CsoundObj.inputMessageAsync) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getControlChannel(channelName)](#CsoundObj.getControlChannel) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.setControlChannel(channelName, value)](#CsoundObj.setControlChannel) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.getStringChannel(channelName)](#CsoundObj.getStringChannel) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.setStringChannel(channelName, value)](#CsoundObj.setStringChannel) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.getOutputName()](#CsoundObj.getOutputName) ⇒ <code>Promise.<string></code>
|
||||||
|
* [.getInputName()](#CsoundObj.getInputName) ⇒ <code>Promise.<string></code>
|
||||||
|
* [.destroy()](#CsoundObj.destroy) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.getAPIVersion()](#CsoundObj.getAPIVersion) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getVersion()](#CsoundObj.getVersion) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.initialize()](#CsoundObj.initialize) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.parseOrc(orc)](#CsoundObj.parseOrc) ⇒ <code>Promise.<object></code>
|
||||||
|
* [.compileTree(tree)](#CsoundObj.compileTree) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.compileOrc(orc)](#CsoundObj.compileOrc) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.evalCode(orc)](#CsoundObj.evalCode) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.start()](#CsoundObj.start) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.compileCsd(path)](#CsoundObj.compileCsd) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.compileCsdText(orc)](#CsoundObj.compileCsdText) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.perform()](#CsoundObj.perform) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.performKsmps()](#CsoundObj.performKsmps) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.performBuffer()](#CsoundObj.performBuffer) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.stop()](#CsoundObj.stop) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.cleanup()](#CsoundObj.cleanup) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.reset()](#CsoundObj.reset) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getInputBufferSize()](#CsoundObj.getInputBufferSize) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getOutputBufferSize()](#CsoundObj.getOutputBufferSize) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getInputBuffer()](#CsoundObj.getInputBuffer) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getOutputBuffer()](#CsoundObj.getOutputBuffer) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getSpin()](#CsoundObj.getSpin) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getSpout()](#CsoundObj.getSpout) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getMIDIDevList(isOutput)](#CsoundObj.getMIDIDevList) ⇒ [<code>Promise.<CS\_MIDIDEVICE></code>](#CS_MIDIDEVICE)
|
||||||
|
* [.getRtMidiName()](#CsoundObj.getRtMidiName) ⇒ <code>Promise.<string></code>
|
||||||
|
* [.midiMessage(midi, midi, midi)](#CsoundObj.midiMessage) ⇒ <code>Promise.<void></code>
|
||||||
|
* [.isScorePending()](#CsoundObj.isScorePending) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.setScorePending(pending)](#CsoundObj.setScorePending) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.readScore(score)](#CsoundObj.readScore) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.getScoreTime()](#CsoundObj.getScoreTime) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getScoreOffsetSeconds()](#CsoundObj.getScoreOffsetSeconds) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.setScoreOffsetSeconds(time)](#CsoundObj.setScoreOffsetSeconds) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.rewindScore()](#CsoundObj.rewindScore) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.tableLength(tableNum)](#CsoundObj.tableLength) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.tableGet(tableNum, tableIndex)](#CsoundObj.tableGet) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.tableSet(tableNum, tableIndex, value)](#CsoundObj.tableSet) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.tableCopyIn(tableNum, tableIndex, array)](#CsoundObj.tableCopyIn) ⇒ <code>Promise.<undefined></code>
|
||||||
|
* [.tableCopyOut(tableNum)](#CsoundObj.tableCopyOut) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
* [.getTableArgs(tableNum)](#CsoundObj.getTableArgs) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
* [.isNamedGEN(tableNum)](#CsoundObj.isNamedGEN) ⇒ <code>Promise.<number></code>
|
||||||
|
* [.getNamedGEN(tableNum)](#CsoundObj.getNamedGEN) ⇒ <code>Promise.<(string\|undefined)></code>
|
||||||
|
|
||||||
|
<a name="getTable"></a>
|
||||||
|
|
||||||
|
### CsoundObjgetTable(tableNum) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
**Kind**: global method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.fs"></a>
|
||||||
|
|
||||||
|
### CsoundObj.fs : <code>IFs:memfs</code>
|
||||||
|
The in-browser filesystem based on nodejs's
|
||||||
|
built-in module "fs"
|
||||||
|
|
||||||
|
**Kind**: static property of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.eventNames"></a>
|
||||||
|
|
||||||
|
### CsoundObj.eventNames() ⇒ <code>Array.<string></code>
|
||||||
|
Returns an array listing the events for which the emitter has registered listeners.
|
||||||
|
The values in the array are strings.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.listenerCount"></a>
|
||||||
|
|
||||||
|
### CsoundObj.listenerCount() ⇒ <code>number</code>
|
||||||
|
Returns the number of listeners listening to the event named eventName.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.listeners"></a>
|
||||||
|
|
||||||
|
### CsoundObj.listeners(eventName) ⇒ <code>Array.<function()></code>
|
||||||
|
Returns a copy of the array of listeners for the event named eventName.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
|
||||||
|
<a name="CsoundObj.off"></a>
|
||||||
|
|
||||||
|
### CsoundObj.off(eventName, listener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Alias for removeListener()
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
| listener | <code>function</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.on"></a>
|
||||||
|
|
||||||
|
### CsoundObj.on(eventName, listener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Adds the listener function to the end of the listeners array for the event named eventName.
|
||||||
|
No checks are made to see if the listener has already been added.
|
||||||
|
Multiple calls passing the same combination of eventName and listener
|
||||||
|
will result in the listener being added, and called, multiple times.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
| listener | <code>function</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.addListener"></a>
|
||||||
|
|
||||||
|
### CsoundObj.addListener(eventName, listener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Alias for "on"
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
| listener | <code>function</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.once"></a>
|
||||||
|
|
||||||
|
### CsoundObj.once(eventName, listener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Adds a one-time listener function for the event named eventName.
|
||||||
|
The next time eventName is triggered, this listener is removed and then invoked.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
| listener | <code>function</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.removeAllListeners"></a>
|
||||||
|
|
||||||
|
### CsoundObj.removeAllListeners(eventName) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Removes all listeners, or those of the specified eventName.
|
||||||
|
It is bad practice to remove listeners added elsewhere in the code,
|
||||||
|
particularly when the EventEmitter instance was created by some other
|
||||||
|
component or module.
|
||||||
|
Returns a reference to the EventEmitter, so that calls can be chained.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
|
||||||
|
<a name="CsoundObj.removeListener"></a>
|
||||||
|
|
||||||
|
### CsoundObj.removeListener(eventName, listener) ⇒ <code>external:EventEmitter</code>
|
||||||
|
Removes the specified listener from the listener array for the event named eventName.
|
||||||
|
removeListener() will remove, at most, one instance of a listener from the listener array.
|
||||||
|
If any single listener has been added multiple times to the listener array for the specified eventName,
|
||||||
|
then removeListener() must be called multiple times to remove each instance.
|
||||||
|
Removes the specified listener from the listener array for the event named eventName.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| eventName | [<code>PublicEvents</code>](#PublicEvents) |
|
||||||
|
| listener | <code>function</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getSr"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getSr() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the sample rate from Csound instance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getKr"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getKr() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the control rate from Csound instance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getKsmps"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getKsmps() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the ksmps value (kr/sr) from Csound instance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getNchnls"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getNchnls() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the number of output channels from Csound instance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getNchnlsInput"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getNchnlsInput() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the number of input channels from Csound instance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.get0dBFS"></a>
|
||||||
|
|
||||||
|
### CsoundObj.get0dBFS() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the value of csoundGet0dBFS
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getA4"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getA4() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the A4 frequency reference
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getCurrentTimeSamples"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getCurrentTimeSamples() ⇒ <code>Promise.<number></code>
|
||||||
|
Return the current performance time in samples
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getSizeOfMYFLT"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getSizeOfMYFLT() ⇒ <code>Promise.<number></code>
|
||||||
|
Return the size of MYFLT in number of bytes
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.setOption"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setOption(option) ⇒ <code>Promise.<number></code>
|
||||||
|
Set a single csound option (flag),
|
||||||
|
no spaces are allowed in the string.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| option | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.setParams"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setParams(csoundParams) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Configure Csound with a given set of
|
||||||
|
parameters defined in the CSOUND_PARAMS structure.
|
||||||
|
These parameters are the part of the OPARMS struct
|
||||||
|
that are configurable through command line flags.
|
||||||
|
The CSOUND_PARAMS structure can be obtained using
|
||||||
|
csoundGetParams().
|
||||||
|
These options should only be changed before
|
||||||
|
performance has started.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| csoundParams | [<code>CSOUND\_PARAMS</code>](#CSOUND_PARAMS) | csoundParams object |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getParams"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getParams() ⇒ [<code>Promise.<CSOUND\_PARAMS></code>](#CSOUND_PARAMS)
|
||||||
|
Get the current set of parameters
|
||||||
|
from a Csound instance
|
||||||
|
in a CSOUND_PARAMS structure.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
**Returns**: [<code>Promise.<CSOUND\_PARAMS></code>](#CSOUND_PARAMS) - - CSOUND_PARAMS object
|
||||||
|
<a name="CsoundObj.getDebug"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getDebug() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns whether Csound is set to print debug messages
|
||||||
|
sent through the DebugMsg() internal API function.
|
||||||
|
Anything different to 0 means true.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.setDebug"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setDebug(debug) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Return the size of MYFLT in number of bytes
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| debug | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.inputMessage"></a>
|
||||||
|
|
||||||
|
### CsoundObj.inputMessage(scoreEvent) ⇒ <code>Promise.<number></code>
|
||||||
|
Inputs an immediate score event
|
||||||
|
without any pre-process parsing
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| scoreEvent | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.inputMessageAsync"></a>
|
||||||
|
|
||||||
|
### CsoundObj.inputMessageAsync(scoreEvent) ⇒ <code>Promise.<number></code>
|
||||||
|
Inputs an immediate score event
|
||||||
|
without any pre-process parsing
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| scoreEvent | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getControlChannel"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getControlChannel(channelName) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Retrieves the value of control channel identified by channelName.
|
||||||
|
If the err argument is not NULL, the error (or success) code finding
|
||||||
|
or accessing the channel is stored in it.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| channelName | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.setControlChannel"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setControlChannel(channelName, value) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Sets the value of control channel identified by channelName
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| channelName | <code>string</code> |
|
||||||
|
| value | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getStringChannel"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getStringChannel(channelName) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Retrieves the string channel identified by channelName
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| channelName | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.setStringChannel"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setStringChannel(channelName, value) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Sets the string channel value identified by channelName
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| channelName | <code>string</code> |
|
||||||
|
| value | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getOutputName"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getOutputName() ⇒ <code>Promise.<string></code>
|
||||||
|
Returns the audio output name (-o)
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getInputName"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getInputName() ⇒ <code>Promise.<string></code>
|
||||||
|
Returns the audio input name (-i)
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.destroy"></a>
|
||||||
|
|
||||||
|
### CsoundObj.destroy() ⇒ <code>Promise.<undefined></code>
|
||||||
|
Destroys an instance of Csound and frees memory
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getAPIVersion"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getAPIVersion() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the API version as int
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getVersion"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getVersion() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the Csound version as int
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.initialize"></a>
|
||||||
|
|
||||||
|
### CsoundObj.initialize() ⇒ <code>Promise.<number></code>
|
||||||
|
Initialise Csound with specific flags.
|
||||||
|
This function is called internally by csoundCreate(),
|
||||||
|
so there is generally no need to use it explicitly
|
||||||
|
unless you need to avoid default initilization that
|
||||||
|
sets signal handlers and atexit() callbacks.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
**Returns**: <code>Promise.<number></code> - - Return value is zero on success,
|
||||||
|
positive if initialisation was done already, and negative on error.
|
||||||
|
<a name="CsoundObj.parseOrc"></a>
|
||||||
|
|
||||||
|
### CsoundObj.parseOrc(orc) ⇒ <code>Promise.<object></code>
|
||||||
|
Parses a csound orchestra string
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| orc | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.compileTree"></a>
|
||||||
|
|
||||||
|
### CsoundObj.compileTree(tree) ⇒ <code>Promise.<number></code>
|
||||||
|
Compiles AST tree
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tree | <code>object</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.compileOrc"></a>
|
||||||
|
|
||||||
|
### CsoundObj.compileOrc(orc) ⇒ <code>Promise.<number></code>
|
||||||
|
Compiles a csound orchestra string
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| orc | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.evalCode"></a>
|
||||||
|
|
||||||
|
### CsoundObj.evalCode(orc) ⇒ <code>Promise.<number></code>
|
||||||
|
Compiles a csound orchestra string
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| orc | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.start"></a>
|
||||||
|
|
||||||
|
### CsoundObj.start() ⇒ <code>Promise.<number></code>
|
||||||
|
Prepares Csound for performance
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.compileCsd"></a>
|
||||||
|
|
||||||
|
### CsoundObj.compileCsd(path) ⇒ <code>Promise.<number></code>
|
||||||
|
Compiles a Csound input file but does not perform it.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| path | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.compileCsdText"></a>
|
||||||
|
|
||||||
|
### CsoundObj.compileCsdText(orc) ⇒ <code>Promise.<number></code>
|
||||||
|
Compiles a CSD string but does not perform it.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| orc | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.perform"></a>
|
||||||
|
|
||||||
|
### CsoundObj.perform() ⇒ <code>Promise.<number></code>
|
||||||
|
Performs(plays) audio until end is reached
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.performKsmps"></a>
|
||||||
|
|
||||||
|
### CsoundObj.performKsmps() ⇒ <code>Promise.<number></code>
|
||||||
|
Performs(plays) 1 ksmps worth of sample(s)
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.performBuffer"></a>
|
||||||
|
|
||||||
|
### CsoundObj.performBuffer() ⇒ <code>Promise.<number></code>
|
||||||
|
Performs(plays) 1 buffer worth of audio
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.stop"></a>
|
||||||
|
|
||||||
|
### CsoundObj.stop() ⇒ <code>Promise.<undefined></code>
|
||||||
|
Stops a csoundPerform
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.cleanup"></a>
|
||||||
|
|
||||||
|
### CsoundObj.cleanup() ⇒ <code>Promise.<number></code>
|
||||||
|
Prints information about the end of a performance,
|
||||||
|
and closes audio and MIDI devices.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.reset"></a>
|
||||||
|
|
||||||
|
### CsoundObj.reset() ⇒ <code>Promise.<number></code>
|
||||||
|
Prints information about the end of a performance,
|
||||||
|
and closes audio and MIDI devices.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getInputBufferSize"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getInputBufferSize() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the number of samples in Csound's input buffer.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getOutputBufferSize"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getOutputBufferSize() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the number of samples in Csound's output buffer.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getInputBuffer"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getInputBuffer() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the address of the Csound audio input buffer.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getOutputBuffer"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getOutputBuffer() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the address of the Csound audio output buffer.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getSpin"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getSpin() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the address of the Csound audio input working buffer (spin).
|
||||||
|
Enables external software to write audio into Csound before calling csoundPerformKsmps.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getSpout"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getSpout() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the address of the Csound audio output working buffer (spout).
|
||||||
|
Enables external software to read audio from Csound after calling csoundPerformKsmps.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getMIDIDevList"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getMIDIDevList(isOutput) ⇒ [<code>Promise.<CS\_MIDIDEVICE></code>](#CS_MIDIDEVICE)
|
||||||
|
This function can be called to obtain a list of available input or output midi devices.
|
||||||
|
If list is NULL, the function will only return the number of devices
|
||||||
|
(isOutput=1 for out devices, 0 for in devices).
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| isOutput | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getRtMidiName"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getRtMidiName() ⇒ <code>Promise.<string></code>
|
||||||
|
This function can be called to obtain a list of available input or output midi devices.
|
||||||
|
If list is NULL, the function will only return the number of devices
|
||||||
|
(isOutput=1 for out devices, 0 for in devices).
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.midiMessage"></a>
|
||||||
|
|
||||||
|
### CsoundObj.midiMessage(midi, midi, midi) ⇒ <code>Promise.<void></code>
|
||||||
|
Emit a midi message with a given triplet of values
|
||||||
|
in the range of 0 to 127.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| midi | <code>number</code> | status value |
|
||||||
|
| midi | <code>number</code> | data1 |
|
||||||
|
| midi | <code>number</code> | data2 |
|
||||||
|
|
||||||
|
<a name="CsoundObj.isScorePending"></a>
|
||||||
|
|
||||||
|
### CsoundObj.isScorePending() ⇒ <code>Promise.<number></code>
|
||||||
|
Sees whether Csound score events are performed or not,
|
||||||
|
independently of real-time MIDI events
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.setScorePending"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setScorePending(pending) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Sets whether Csound score events are performed or not
|
||||||
|
(real-time events will continue to be performed).
|
||||||
|
Can be used by external software, such as a VST host,
|
||||||
|
to turn off performance of score events (while continuing to perform real-time events),
|
||||||
|
for example to mute a Csound score while working on other tracks of a piece,
|
||||||
|
or to play the Csound instruments live.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| pending | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.readScore"></a>
|
||||||
|
|
||||||
|
### CsoundObj.readScore(score) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Read, preprocess, and load a score from an ASCII string It can be called repeatedly,
|
||||||
|
with the new score events being added to the currently scheduled ones.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| score | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getScoreTime"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getScoreTime() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the current score time in seconds since the beginning of performance.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.getScoreOffsetSeconds"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getScoreOffsetSeconds() ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the score time beginning at which score events will actually immediately be performed
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.setScoreOffsetSeconds"></a>
|
||||||
|
|
||||||
|
### CsoundObj.setScoreOffsetSeconds(time) ⇒ <code>Promise.<number></code>
|
||||||
|
Csound score events prior to the specified time are not performed,
|
||||||
|
and performance begins immediately at the specified time
|
||||||
|
(real-time events will continue to be performed as they are received).
|
||||||
|
Can be used by external software, such as a VST host, to begin
|
||||||
|
score performance midway through a Csound score,
|
||||||
|
for example to repeat a loop in a sequencer,
|
||||||
|
or to synchronize other events with the Csound score.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| time | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.rewindScore"></a>
|
||||||
|
|
||||||
|
### CsoundObj.rewindScore() ⇒ <code>Promise.<number></code>
|
||||||
|
Rewinds a compiled Csound score to the time specified with csoundObj.setScoreOffsetSeconds().
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
<a name="CsoundObj.tableLength"></a>
|
||||||
|
|
||||||
|
### CsoundObj.tableLength(tableNum) ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the length of a function table
|
||||||
|
(not including the guard point),
|
||||||
|
or -1 if the table does not exist.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.tableGet"></a>
|
||||||
|
|
||||||
|
### CsoundObj.tableGet(tableNum, tableIndex) ⇒ <code>Promise.<number></code>
|
||||||
|
Returns the value of a slot in a function table.
|
||||||
|
The table number and index are assumed to be valid.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
| tableIndex | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.tableSet"></a>
|
||||||
|
|
||||||
|
### CsoundObj.tableSet(tableNum, tableIndex, value) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Sets the value of a slot in a function table.
|
||||||
|
The table number and index are assumed to be valid.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
| tableIndex | <code>string</code> |
|
||||||
|
| value | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.tableCopyIn"></a>
|
||||||
|
|
||||||
|
### CsoundObj.tableCopyIn(tableNum, tableIndex, array) ⇒ <code>Promise.<undefined></code>
|
||||||
|
Copy the contents of an Array or TypedArray from javascript into a given csound function table.
|
||||||
|
The table number is assumed to be valid, and the table needs to have sufficient space
|
||||||
|
to receive all the array contents.
|
||||||
|
The table number and index are assumed to be valid.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
| tableIndex | <code>string</code> |
|
||||||
|
| array | <code>Array.<number></code> \| <code>ArrayLike.<number></code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.tableCopyOut"></a>
|
||||||
|
|
||||||
|
### CsoundObj.tableCopyOut(tableNum) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
Copies the contents of a function table from csound into Float64Array.
|
||||||
|
The function returns a Float64Array if the table exists, otherwise
|
||||||
|
it returns undefined.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getTableArgs"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getTableArgs(tableNum) ⇒ <code>Promise.<(Float64Array\|undefined)></code>
|
||||||
|
Copies the contents of a function table from csound into Float64Array.
|
||||||
|
The function returns a Float64Array if the table exists, otherwise
|
||||||
|
it returns undefined.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.isNamedGEN"></a>
|
||||||
|
|
||||||
|
### CsoundObj.isNamedGEN(tableNum) ⇒ <code>Promise.<number></code>
|
||||||
|
Checks if a given GEN number num is a named GEN if so,
|
||||||
|
it returns the string length (excluding terminating NULL char).
|
||||||
|
Otherwise it returns 0.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="CsoundObj.getNamedGEN"></a>
|
||||||
|
|
||||||
|
### CsoundObj.getNamedGEN(tableNum) ⇒ <code>Promise.<(string\|undefined)></code>
|
||||||
|
Gets the GEN name from a number num, if this is a named GEN.
|
||||||
|
If the table number doesn't represent a named GEN, it will
|
||||||
|
return undefined.
|
||||||
|
|
||||||
|
**Kind**: static method of [<code>CsoundObj</code>](#CsoundObj)
|
||||||
|
|
||||||
|
| Param | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| tableNum | <code>string</code> |
|
||||||
|
|
||||||
|
<a name="PublicEvents"></a>
|
||||||
|
|
||||||
|
## PublicEvents : <code>enum</code>
|
||||||
|
**Kind**: global enum
|
||||||
|
**Read only**: true
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| "play" | <code>string</code> | called anytime performance goes from pause/stop to a running state. |
|
||||||
|
| "pause" | <code>string</code> | called after any successful csound.pause() calls. |
|
||||||
|
| "stop" | <code>string</code> | called after end of performance or after a successful csound.stop(). |
|
||||||
|
| "realtimePerformanceStarted" | <code>string</code> | called at the start of realtime performance but not on resume or render. |
|
||||||
|
| "realtimePerformancePaused" | <code>string</code> | only called if csound.pause() was successfully called during performance. |
|
||||||
|
| "realtimePerformanceResumed" | <code>string</code> | only called if csound.resume() was successfully called after a pause. |
|
||||||
|
| "realtimePerformanceEnded" | <code>string</code> | called after end of performance or after a successful csound.stop(). |
|
||||||
|
| "renderStarted" | <code>string</code> | called at the start of offline/non-realtime render to disk. |
|
||||||
|
| "renderEnded" | <code>string</code> | called at the end of offline/non-realtime render to disk. |
|
||||||
|
| "onAudioNodeCreated" | <code>string</code> | called when an audioNode is created from the AudioContext before realtime performance. the event callback will include the audioNode itself, which is needed if autoConnect is set to false. |
|
||||||
|
| "message" | <code>string</code> | the main entrypoint to csound's messaging (-m) system, a default event listener will print the message to the browser console, this default listener can be removed by the user. |
|
||||||
|
|
||||||
|
<a name="Csound"></a>
|
||||||
|
|
||||||
|
## Csound([params]) ⇒ <code>Promise.<(CsoundObj\|undefined)></code>
|
||||||
|
The default entry for @csound/wasm/browser module.
|
||||||
|
If loaded successfully, it returns CsoundObj,
|
||||||
|
otherwise undefined.
|
||||||
|
|
||||||
|
**Kind**: global function
|
||||||
|
|
||||||
|
| Param | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| [params] | <code>Object</code> | | Initialization parameters |
|
||||||
|
| [params.audioContext] | <code>AudioContext</code> | | Optional AudioContext to use; if none given, an AudioContext will be created. |
|
||||||
|
| [params.inputChannelCount] | <code>Number</code> | | Optional input channel count for AudioNode used with WebAudio graph. Defaults to the value of nchnls_i in useWorker but 2 otherwise. |
|
||||||
|
| [params.outputChannelCount] | <code>Number</code> | | Optional output channel count AudioNode used with WebAudio graph. Defaults to the value of nchnls in useWorker but 2 otherwise. |
|
||||||
|
| [params.autoConnect] | <code>Boolean</code> | <code>true</code> | Set to configure Csound to automatically connect to the audioContext.destination output. |
|
||||||
|
| [params.withPlugins] | <code>Array.<Object></code> | | Array of WebAssembly Csound plugin libraries to use with Csound. |
|
||||||
|
| [params.useWorker] | <code>Boolean</code> | <code>false</code> | Configure to use backend using Web Workers to run Csound in a thread separate from audio callback. |
|
||||||
|
| [params.useSAB] | <code>Boolean</code> | <code>true</code> | Configure to use SharedArrayBuffers for WebWorker communications if platform supports it. |
|
||||||
|
| [params.useSPN] | <code>Boolean</code> | <code>false</code> | Configure to use explicitly request ScriptProcessorNode rather than AudioWorklet. Recommended only for debug testing purposes. |
|
||||||
|
|
||||||
|
<a name="CSOUND_PARAMS"></a>
|
||||||
|
|
||||||
|
## CSOUND\_PARAMS
|
||||||
|
**Kind**: global typedef
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| debug_mode | <code>number</code> |
|
||||||
|
| buffer_frames | <code>number</code> |
|
||||||
|
| hardware_buffer_frames | <code>number</code> |
|
||||||
|
| displays | <code>number</code> |
|
||||||
|
| ascii_graphs | <code>number</code> |
|
||||||
|
| postscript_graphs | <code>number</code> |
|
||||||
|
| message_level | <code>number</code> |
|
||||||
|
| tempo | <code>number</code> |
|
||||||
|
| ring_bell | <code>number</code> |
|
||||||
|
| use_cscore | <code>number</code> |
|
||||||
|
| terminate_on_midi | <code>number</code> |
|
||||||
|
| heartbeat | <code>number</code> |
|
||||||
|
| defer_gen01_load | <code>number</code> |
|
||||||
|
| midi_key | <code>number</code> |
|
||||||
|
| midi_key_cps | <code>number</code> |
|
||||||
|
| midi_key_oct | <code>number</code> |
|
||||||
|
| midi_key_pch | <code>number</code> |
|
||||||
|
| midi_velocity | <code>number</code> |
|
||||||
|
|
||||||
|
<a name="CS_MIDIDEVICE"></a>
|
||||||
|
|
||||||
|
## CS\_MIDIDEVICE
|
||||||
|
**Kind**: global typedef
|
||||||
|
**Properties**
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| --- | --- |
|
||||||
|
| device_name | <code>string</code> |
|
||||||
|
| interface_name | <code>string</code> |
|
||||||
|
| device_id | <code>string</code> |
|
||||||
|
| midi_module | <code>string</code> |
|
||||||
|
| isOutput | <code>number</code> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
217
src/App.svelte
217
src/App.svelte
@ -1,9 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import TopBar from './lib/TopBar.svelte';
|
import TopBar from './lib/TopBar.svelte';
|
||||||
import EditorWithLogs from './lib/EditorWithLogs.svelte';
|
import EditorWithLogs from './lib/EditorWithLogs.svelte';
|
||||||
import EditorSettings from './lib/EditorSettings.svelte';
|
import EditorSettings from './lib/EditorSettings.svelte';
|
||||||
|
import FileBrowser from './lib/FileBrowser.svelte';
|
||||||
import SidePanel from './lib/SidePanel.svelte';
|
import SidePanel from './lib/SidePanel.svelte';
|
||||||
import Popup from './lib/Popup.svelte';
|
import Popup from './lib/Popup.svelte';
|
||||||
|
import { csound, csoundLogs, type LogEntry } from './lib/csound';
|
||||||
|
import { projectManager, type CsoundProject } from './lib/project-system';
|
||||||
|
import ConfirmDialog from './lib/ConfirmDialog.svelte';
|
||||||
|
import InputDialog from './lib/InputDialog.svelte';
|
||||||
import {
|
import {
|
||||||
PanelLeftClose,
|
PanelLeftClose,
|
||||||
PanelLeftOpen,
|
PanelLeftOpen,
|
||||||
@ -11,17 +17,54 @@
|
|||||||
PanelRightOpen,
|
PanelRightOpen,
|
||||||
PanelBottomClose,
|
PanelBottomClose,
|
||||||
PanelBottomOpen,
|
PanelBottomOpen,
|
||||||
LayoutGrid
|
LayoutGrid,
|
||||||
|
Save
|
||||||
} from 'lucide-svelte';
|
} from 'lucide-svelte';
|
||||||
|
|
||||||
let sidePanelVisible = $state(true);
|
let sidePanelVisible = $state(true);
|
||||||
let sidePanelPosition = $state<'left' | 'right' | 'bottom'>('right');
|
let sidePanelPosition = $state<'left' | 'right' | 'bottom'>('right');
|
||||||
let popupVisible = $state(false);
|
let popupVisible = $state(false);
|
||||||
let editorValue = $state('// Start coding here...\n');
|
let editorValue = $state('<CsoundSynthesizer>\n<CsOptions>\n-odac\n</CsOptions>\n<CsInstruments>\n\nsr = 44100\nksmps = 32\nnchnls = 2\n0dbfs = 1\n\ninstr 1\n aOut oscili 0.5, 440\n outs aOut, aOut\nendin\n\n</CsInstruments>\n<CsScore>\ni 1 0 2\n</CsScore>\n</CsoundSynthesizer>\n');
|
||||||
let interpreterLogs = $state<string[]>([]);
|
let interpreterLogs = $state<LogEntry[]>([]);
|
||||||
|
|
||||||
let sidePanelRef: SidePanel;
|
let sidePanelRef: SidePanel;
|
||||||
let editorRef: EditorWithLogs;
|
let editorRef: EditorWithLogs;
|
||||||
|
let fileBrowserRef: FileBrowser;
|
||||||
|
let currentProjectId = $state<string | null>(null);
|
||||||
|
let hasUnsavedChanges = $state(false);
|
||||||
|
let isNewUnsavedBuffer = $state(false);
|
||||||
|
let pendingProject: CsoundProject | null = null;
|
||||||
|
let showUnsavedDialog = $state(false);
|
||||||
|
let showSaveAsDialog = $state(false);
|
||||||
|
|
||||||
|
const TEMPLATE_CONTENT = '<CsoundSynthesizer>\n<CsOptions>\n-odac\n</CsOptions>\n<CsInstruments>\n\nsr = 44100\nksmps = 32\nnchnls = 2\n0dbfs = 1\n\ninstr 1\n aOut oscili 0.5, 440\n outs aOut, aOut\nendin\n\n</CsInstruments>\n<CsScore>\ni 1 0 2\n</CsScore>\n</CsoundSynthesizer>\n';
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await csound.init();
|
||||||
|
await projectManager.init();
|
||||||
|
|
||||||
|
const result = await projectManager.getAllProjects();
|
||||||
|
if (result.success && result.data.length === 0) {
|
||||||
|
await projectManager.createProject({
|
||||||
|
title: 'Template',
|
||||||
|
author: 'System',
|
||||||
|
content: TEMPLATE_CONTENT,
|
||||||
|
tags: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsubscribe = csoundLogs.subscribe(logs => {
|
||||||
|
interpreterLogs = logs;
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(async () => {
|
||||||
|
await csound.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
function toggleSidePanel() {
|
function toggleSidePanel() {
|
||||||
sidePanelVisible = !sidePanelVisible;
|
sidePanelVisible = !sidePanelVisible;
|
||||||
@ -33,6 +76,121 @@
|
|||||||
|
|
||||||
function handleEditorChange(value: string) {
|
function handleEditorChange(value: string) {
|
||||||
editorValue = value;
|
editorValue = value;
|
||||||
|
hasUnsavedChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNewFile() {
|
||||||
|
if (hasUnsavedChanges) {
|
||||||
|
pendingProject = null;
|
||||||
|
showUnsavedDialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createNewBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewBuffer() {
|
||||||
|
currentProjectId = null;
|
||||||
|
editorValue = TEMPLATE_CONTENT;
|
||||||
|
hasUnsavedChanges = false;
|
||||||
|
isNewUnsavedBuffer = true;
|
||||||
|
if (editorRef) {
|
||||||
|
editorRef.setValue(TEMPLATE_CONTENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleFileSelect(project: CsoundProject | null) {
|
||||||
|
if (hasUnsavedChanges) {
|
||||||
|
pendingProject = project;
|
||||||
|
showUnsavedDialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project) {
|
||||||
|
loadProject(project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadProject(project: CsoundProject) {
|
||||||
|
currentProjectId = project.id;
|
||||||
|
editorValue = project.content;
|
||||||
|
hasUnsavedChanges = false;
|
||||||
|
isNewUnsavedBuffer = false;
|
||||||
|
if (editorRef) {
|
||||||
|
editorRef.setValue(project.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveCurrentProject() {
|
||||||
|
if (isNewUnsavedBuffer) {
|
||||||
|
showSaveAsDialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentProjectId) return;
|
||||||
|
|
||||||
|
const result = await projectManager.updateProject({
|
||||||
|
id: currentProjectId,
|
||||||
|
content: editorValue
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
hasUnsavedChanges = false;
|
||||||
|
if (fileBrowserRef) {
|
||||||
|
fileBrowserRef.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSaveAs(title: string) {
|
||||||
|
const finalTitle = title.trim() || 'Untitled';
|
||||||
|
|
||||||
|
const result = await projectManager.createProject({
|
||||||
|
title: finalTitle,
|
||||||
|
author: 'Anonymous',
|
||||||
|
content: editorValue,
|
||||||
|
tags: []
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
currentProjectId = result.data.id;
|
||||||
|
hasUnsavedChanges = false;
|
||||||
|
isNewUnsavedBuffer = false;
|
||||||
|
if (fileBrowserRef) {
|
||||||
|
fileBrowserRef.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleMetadataUpdate(projectId: string, updates: { title?: string; author?: string }) {
|
||||||
|
const result = await projectManager.updateProject({
|
||||||
|
id: projectId,
|
||||||
|
...updates
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success && fileBrowserRef) {
|
||||||
|
fileBrowserRef.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSaveAndSwitch() {
|
||||||
|
saveCurrentProject().then(() => {
|
||||||
|
if (pendingProject) {
|
||||||
|
loadProject(pendingProject);
|
||||||
|
} else {
|
||||||
|
createNewBuffer();
|
||||||
|
}
|
||||||
|
pendingProject = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDiscardAndSwitch() {
|
||||||
|
if (pendingProject) {
|
||||||
|
loadProject(pendingProject);
|
||||||
|
} else {
|
||||||
|
createNewBuffer();
|
||||||
|
}
|
||||||
|
pendingProject = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cyclePanelPosition() {
|
function cyclePanelPosition() {
|
||||||
@ -64,18 +222,26 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet filesTabContent()}
|
{#snippet filesTabContent()}
|
||||||
<h3>File Browser</h3>
|
<FileBrowser
|
||||||
<p>Your project files will be listed here.</p>
|
bind:this={fileBrowserRef}
|
||||||
<ul>
|
onFileSelect={handleFileSelect}
|
||||||
<li>src/</li>
|
onNewFile={handleNewFile}
|
||||||
<li>├── App.svelte</li>
|
onMetadataUpdate={handleMetadataUpdate}
|
||||||
<li>├── main.ts</li>
|
selectedProjectId={currentProjectId}
|
||||||
<li>└── lib/</li>
|
/>
|
||||||
</ul>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<TopBar title="oldboy">
|
<TopBar title="oldboy">
|
||||||
|
<button
|
||||||
|
class="icon-button"
|
||||||
|
onclick={saveCurrentProject}
|
||||||
|
disabled={!hasUnsavedChanges}
|
||||||
|
title="Save {hasUnsavedChanges ? '(unsaved changes)' : ''}"
|
||||||
|
class:has-changes={hasUnsavedChanges}
|
||||||
|
>
|
||||||
|
<Save size={18} />
|
||||||
|
</button>
|
||||||
<button onclick={toggleSidePanel} class="icon-button">
|
<button onclick={toggleSidePanel} class="icon-button">
|
||||||
{#if sidePanelVisible}
|
{#if sidePanelVisible}
|
||||||
{#if sidePanelPosition === 'left'}
|
{#if sidePanelPosition === 'left'}
|
||||||
@ -154,6 +320,24 @@
|
|||||||
<p>You can drag it around by the header.</p>
|
<p>You can drag it around by the header.</p>
|
||||||
<p>It stays on top of everything else.</p>
|
<p>It stays on top of everything else.</p>
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:visible={showUnsavedDialog}
|
||||||
|
title="Unsaved Changes"
|
||||||
|
message="You have unsaved changes. What would you like to do?"
|
||||||
|
confirmLabel="Save"
|
||||||
|
cancelLabel="Discard"
|
||||||
|
onConfirm={handleSaveAndSwitch}
|
||||||
|
onCancel={handleDiscardAndSwitch}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputDialog
|
||||||
|
bind:visible={showSaveAsDialog}
|
||||||
|
title="Save As"
|
||||||
|
label="File name"
|
||||||
|
placeholder="Untitled"
|
||||||
|
onConfirm={handleSaveAs}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -192,11 +376,20 @@
|
|||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-button:hover {
|
.icon-button:hover:not(:disabled) {
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
border-color: #646cff;
|
border-color: #646cff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-button:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button.has-changes {
|
||||||
|
color: #646cff;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: rgba(255, 255, 255, 0.87);
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
|||||||
89
src/lib/ConfirmDialog.svelte
Normal file
89
src/lib/ConfirmDialog.svelte
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Modal from './Modal.svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
visible?: boolean;
|
||||||
|
title?: string;
|
||||||
|
message: string;
|
||||||
|
confirmLabel?: string;
|
||||||
|
cancelLabel?: string;
|
||||||
|
onConfirm: () => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
visible = $bindable(false),
|
||||||
|
title = 'Confirm',
|
||||||
|
message,
|
||||||
|
confirmLabel = 'Confirm',
|
||||||
|
cancelLabel = 'Cancel',
|
||||||
|
onConfirm,
|
||||||
|
onCancel
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
visible = false;
|
||||||
|
onConfirm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
visible = false;
|
||||||
|
onCancel?.();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:visible {title}>
|
||||||
|
<div class="confirm-dialog">
|
||||||
|
<p>{message}</p>
|
||||||
|
<div class="button-group">
|
||||||
|
<button class="button button-secondary" onclick={handleCancel}>
|
||||||
|
{cancelLabel}
|
||||||
|
</button>
|
||||||
|
<button class="button button-primary" onclick={handleConfirm}>
|
||||||
|
{confirmLabel}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.confirm-dialog p {
|
||||||
|
margin: 0 0 1.5rem 0;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
|
background-color: #646cff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary:hover {
|
||||||
|
background-color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary {
|
||||||
|
background-color: transparent;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -14,6 +14,7 @@
|
|||||||
import { oneDark } from '@codemirror/theme-one-dark';
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
import { vim } from '@replit/codemirror-vim';
|
import { vim } from '@replit/codemirror-vim';
|
||||||
import { editorSettings } from './stores/editorSettings';
|
import { editorSettings } from './stores/editorSettings';
|
||||||
|
import { csound } from './csound';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
@ -40,6 +41,19 @@
|
|||||||
const lineWrappingCompartment = new Compartment();
|
const lineWrappingCompartment = new Compartment();
|
||||||
const vimCompartment = new Compartment();
|
const vimCompartment = new Compartment();
|
||||||
|
|
||||||
|
const evaluateKeymap = keymap.of([
|
||||||
|
{
|
||||||
|
key: 'Mod-e',
|
||||||
|
run: (view) => {
|
||||||
|
const code = view.state.doc.toString();
|
||||||
|
csound.evaluate(code).catch(err => {
|
||||||
|
console.error('Evaluation error:', err);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const settings = $editorSettings;
|
const settings = $editorSettings;
|
||||||
|
|
||||||
@ -75,6 +89,7 @@
|
|||||||
...baseExtensions,
|
...baseExtensions,
|
||||||
languageExtensions[language],
|
languageExtensions[language],
|
||||||
oneDark,
|
oneDark,
|
||||||
|
evaluateKeymap,
|
||||||
lineNumbersCompartment.of(settings.showLineNumbers ? lineNumbers() : []),
|
lineNumbersCompartment.of(settings.showLineNumbers ? lineNumbers() : []),
|
||||||
lineWrappingCompartment.of(settings.enableLineWrapping ? EditorView.lineWrapping : []),
|
lineWrappingCompartment.of(settings.enableLineWrapping ? EditorView.lineWrapping : []),
|
||||||
vimCompartment.of(settings.vimMode ? vim() : []),
|
vimCompartment.of(settings.vimMode ? vim() : []),
|
||||||
|
|||||||
@ -67,14 +67,6 @@
|
|||||||
export function setValue(value: string): void {
|
export function setValue(value: string): void {
|
||||||
editorRef?.setValue(value);
|
editorRef?.setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addLog(message: string): void {
|
|
||||||
logPanelRef?.addLog(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearLogs(): void {
|
|
||||||
logPanelRef?.clearLogs();
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="editor-with-logs">
|
<div class="editor-with-logs">
|
||||||
|
|||||||
347
src/lib/FileBrowser.svelte
Normal file
347
src/lib/FileBrowser.svelte
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { File, Plus, Trash2 } from 'lucide-svelte';
|
||||||
|
import { projectManager, type CsoundProject } from './project-system';
|
||||||
|
import ConfirmDialog from './ConfirmDialog.svelte';
|
||||||
|
import InputDialog from './InputDialog.svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onFileSelect?: (project: CsoundProject | null) => void;
|
||||||
|
onNewFile?: () => void;
|
||||||
|
onMetadataUpdate?: (projectId: string, updates: { title?: string; author?: string }) => void;
|
||||||
|
selectedProjectId?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { onFileSelect, onNewFile, onMetadataUpdate, selectedProjectId = null }: Props = $props();
|
||||||
|
|
||||||
|
let projects = $state<CsoundProject[]>([]);
|
||||||
|
let loading = $state(true);
|
||||||
|
let showDeleteConfirm = $state(false);
|
||||||
|
let projectToDelete = $state<CsoundProject | null>(null);
|
||||||
|
|
||||||
|
let selectedProject = $derived(
|
||||||
|
projects.find(p => p.id === selectedProjectId) || null
|
||||||
|
);
|
||||||
|
|
||||||
|
let editTitle = $state('');
|
||||||
|
let editAuthor = $state('');
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (selectedProject) {
|
||||||
|
editTitle = selectedProject.title;
|
||||||
|
editAuthor = selectedProject.author;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function refresh() {
|
||||||
|
await loadProjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await loadProjects();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function loadProjects() {
|
||||||
|
loading = true;
|
||||||
|
try {
|
||||||
|
await projectManager.init();
|
||||||
|
const result = await projectManager.getAllProjects();
|
||||||
|
if (result.success) {
|
||||||
|
projects = result.data.sort((a, b) =>
|
||||||
|
new Date(b.dateModified).getTime() - new Date(a.dateModified).getTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load projects:', error);
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleNewFile() {
|
||||||
|
onNewFile?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectProject(project: CsoundProject) {
|
||||||
|
onFileSelect?.(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDeleteClick(project: CsoundProject, event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
projectToDelete = project;
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmDelete() {
|
||||||
|
if (!projectToDelete) return;
|
||||||
|
|
||||||
|
const result = await projectManager.deleteProject(projectToDelete.id);
|
||||||
|
if (result.success) {
|
||||||
|
await loadProjects();
|
||||||
|
}
|
||||||
|
projectToDelete = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(dateString: string): string {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMetadataChange() {
|
||||||
|
if (!selectedProject) return;
|
||||||
|
|
||||||
|
const hasChanges =
|
||||||
|
editTitle !== selectedProject.title ||
|
||||||
|
editAuthor !== selectedProject.author;
|
||||||
|
|
||||||
|
if (hasChanges) {
|
||||||
|
onMetadataUpdate?.(selectedProject.id, {
|
||||||
|
title: editTitle,
|
||||||
|
author: editAuthor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="file-browser">
|
||||||
|
<div class="browser-header">
|
||||||
|
<span class="browser-title">Files</span>
|
||||||
|
<button class="action-button" onclick={handleNewFile} title="New file">
|
||||||
|
<Plus size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="browser-content">
|
||||||
|
{#if loading}
|
||||||
|
<div class="empty-state">Loading...</div>
|
||||||
|
{:else}
|
||||||
|
<div class="project-list">
|
||||||
|
{#each projects as project}
|
||||||
|
<div
|
||||||
|
class="project-item"
|
||||||
|
class:selected={selectedProjectId === project.id}
|
||||||
|
onclick={() => selectProject(project)}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div class="project-icon">
|
||||||
|
<File size={16} />
|
||||||
|
</div>
|
||||||
|
<div class="project-info">
|
||||||
|
<div class="project-title">{project.title}</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="delete-button"
|
||||||
|
onclick={(e) => handleDeleteClick(project, e)}
|
||||||
|
title="Delete"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if selectedProject}
|
||||||
|
<div class="metadata-editor">
|
||||||
|
<div class="metadata-header">Metadata</div>
|
||||||
|
<div class="metadata-fields">
|
||||||
|
<div class="field">
|
||||||
|
<label for="file-title">Name</label>
|
||||||
|
<input
|
||||||
|
id="file-title"
|
||||||
|
type="text"
|
||||||
|
bind:value={editTitle}
|
||||||
|
onchange={handleMetadataChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="file-author">Author</label>
|
||||||
|
<input
|
||||||
|
id="file-author"
|
||||||
|
type="text"
|
||||||
|
bind:value={editAuthor}
|
||||||
|
onchange={handleMetadataChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:visible={showDeleteConfirm}
|
||||||
|
title="Delete File"
|
||||||
|
message="Are you sure you want to delete '{projectToDelete?.title}'?"
|
||||||
|
confirmLabel="Delete"
|
||||||
|
onConfirm={confirmDelete}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.file-browser {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.75rem;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border-bottom: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-title {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
padding: 0.25rem;
|
||||||
|
background-color: transparent;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button:hover {
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.browser-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-bottom: 1px solid #2a2a2a;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-item:hover {
|
||||||
|
background-color: #252525;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-item.selected {
|
||||||
|
background-color: rgba(100, 108, 255, 0.2);
|
||||||
|
border-left: 3px solid #646cff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-icon {
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-button {
|
||||||
|
padding: 0.25rem;
|
||||||
|
background-color: transparent;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-item:hover .delete-button {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-button:hover {
|
||||||
|
color: rgba(255, 100, 100, 0.9);
|
||||||
|
background-color: rgba(255, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata-editor {
|
||||||
|
border-top: 1px solid #2a2a2a;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata-header {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata-fields {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input {
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input:focus {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
121
src/lib/InputDialog.svelte
Normal file
121
src/lib/InputDialog.svelte
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Modal from './Modal.svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
visible?: boolean;
|
||||||
|
title?: string;
|
||||||
|
label: string;
|
||||||
|
placeholder?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
confirmLabel?: string;
|
||||||
|
cancelLabel?: string;
|
||||||
|
onConfirm: (value: string) => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
visible = $bindable(false),
|
||||||
|
title = 'Input',
|
||||||
|
label,
|
||||||
|
placeholder = '',
|
||||||
|
defaultValue = '',
|
||||||
|
confirmLabel = 'OK',
|
||||||
|
cancelLabel = 'Cancel',
|
||||||
|
onConfirm,
|
||||||
|
onCancel
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
let value = $state(defaultValue);
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
visible = false;
|
||||||
|
onConfirm(value);
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
visible = false;
|
||||||
|
onCancel?.();
|
||||||
|
value = '';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal bind:visible {title}>
|
||||||
|
<div class="input-dialog">
|
||||||
|
<label for="input-field">{label}</label>
|
||||||
|
<input
|
||||||
|
id="input-field"
|
||||||
|
type="text"
|
||||||
|
bind:value
|
||||||
|
{placeholder}
|
||||||
|
/>
|
||||||
|
<div class="button-group">
|
||||||
|
<button class="button button-secondary" onclick={handleCancel}>
|
||||||
|
{cancelLabel}
|
||||||
|
</button>
|
||||||
|
<button class="button button-primary" onclick={handleConfirm}>
|
||||||
|
{confirmLabel}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.input-dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
|
background-color: #646cff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary:hover {
|
||||||
|
background-color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary {
|
||||||
|
background-color: transparent;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,28 +1,73 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { Copy, Trash2 } from 'lucide-svelte';
|
||||||
|
import { csound } from './csound';
|
||||||
|
import type { LogEntry } from './csound';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
logs?: string[];
|
logs?: LogEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { logs = [] }: Props = $props();
|
let { logs = [] }: Props = $props();
|
||||||
|
|
||||||
export function addLog(message: string) {
|
function formatTime(date: Date): string {
|
||||||
logs.push(message);
|
return date.toLocaleTimeString('en-US', {
|
||||||
|
hour12: false,
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
fractionalSecondDigits: 3
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearLogs() {
|
async function copyLogs() {
|
||||||
logs = [];
|
if (logs.length === 0) return;
|
||||||
|
|
||||||
|
const logText = logs
|
||||||
|
.map(log => `[${formatTime(log.timestamp)}] ${log.type.toUpperCase()}: ${log.message}`)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(logText);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy logs:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearLogs() {
|
||||||
|
csound.clearLogs();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="log-panel">
|
<div class="log-panel">
|
||||||
|
<div class="log-header">
|
||||||
|
<span class="log-title">Output</span>
|
||||||
|
<div class="log-actions">
|
||||||
|
<button
|
||||||
|
class="action-button"
|
||||||
|
onclick={copyLogs}
|
||||||
|
disabled={logs.length === 0}
|
||||||
|
title="Copy logs"
|
||||||
|
>
|
||||||
|
<Copy size={14} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="action-button"
|
||||||
|
onclick={clearLogs}
|
||||||
|
disabled={logs.length === 0}
|
||||||
|
title="Clear logs"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="log-content">
|
<div class="log-content">
|
||||||
{#if logs.length === 0}
|
{#if logs.length === 0}
|
||||||
<div class="empty-state">No output yet...</div>
|
<div class="empty-state">No output yet...</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#each logs as log, i}
|
{#each logs as log, i}
|
||||||
<div class="log-entry">
|
<div class="log-entry" class:error={log.type === 'error'}>
|
||||||
<span class="log-index">{i + 1}</span>
|
<span class="log-timestamp">{formatTime(log.timestamp)}</span>
|
||||||
<span class="log-message">{log}</span>
|
<span class="log-message">{log.message}</span>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
@ -37,6 +82,50 @@
|
|||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.log-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border-bottom: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-title {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
padding: 0.25rem;
|
||||||
|
background-color: transparent;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button:hover:not(:disabled) {
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.log-content {
|
.log-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -63,10 +152,19 @@
|
|||||||
background-color: #252525;
|
background-color: #252525;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-index {
|
.log-entry.error {
|
||||||
|
background-color: rgba(255, 0, 0, 0.1);
|
||||||
|
border-left: 3px solid rgba(255, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-entry.error .log-message {
|
||||||
|
color: rgba(255, 100, 100, 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-timestamp {
|
||||||
color: rgba(255, 255, 255, 0.4);
|
color: rgba(255, 255, 255, 0.4);
|
||||||
min-width: 2rem;
|
min-width: 6rem;
|
||||||
text-align: right;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-message {
|
.log-message {
|
||||||
|
|||||||
78
src/lib/Modal.svelte
Normal file
78
src/lib/Modal.svelte
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
visible?: boolean;
|
||||||
|
title?: string;
|
||||||
|
onClose?: () => void;
|
||||||
|
children: Snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { visible = $bindable(false), title = '', onClose, children }: Props = $props();
|
||||||
|
|
||||||
|
function handleBackdropClick(e: MouseEvent) {
|
||||||
|
if (e.target === e.currentTarget) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
visible = false;
|
||||||
|
onClose?.();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if visible}
|
||||||
|
<div class="modal-backdrop" onclick={handleBackdropClick} role="dialog" tabindex="-1">
|
||||||
|
<div class="modal-content">
|
||||||
|
{#if title}
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3>{title}</h3>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="modal-body">
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.modal-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
border: 1px solid #3a3a3a;
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 500px;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-bottom: 1px solid #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
125
src/lib/csound/engine.ts
Normal file
125
src/lib/csound/engine.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { Csound } from '@csound/browser';
|
||||||
|
|
||||||
|
export interface CsoundEngineOptions {
|
||||||
|
onMessage?: (message: string) => void;
|
||||||
|
onError?: (error: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CsoundEngine {
|
||||||
|
private csound: Csound | null = null;
|
||||||
|
private initialized = false;
|
||||||
|
private running = false;
|
||||||
|
private options: CsoundEngineOptions;
|
||||||
|
|
||||||
|
constructor(options: CsoundEngineOptions = {}) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(): Promise<void> {
|
||||||
|
if (this.initialized) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.csound = await Csound();
|
||||||
|
|
||||||
|
this.csound.on('message', (message: string) => {
|
||||||
|
this.options.onMessage?.(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.csound.setOption('-odac');
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
this.log('Csound initialized successfully');
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Failed to initialize Csound';
|
||||||
|
this.error(errorMsg);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async evaluateCode(code: string): Promise<void> {
|
||||||
|
if (!this.initialized || !this.csound) {
|
||||||
|
throw new Error('Csound not initialized. Call init() first.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.running) {
|
||||||
|
await this.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log('Resetting Csound...');
|
||||||
|
await this.csound.reset();
|
||||||
|
|
||||||
|
this.log('Setting audio output...');
|
||||||
|
await this.csound.setOption('-odac');
|
||||||
|
|
||||||
|
const orcMatch = code.match(/<CsInstruments>([\s\S]*?)<\/CsInstruments>/);
|
||||||
|
const scoMatch = code.match(/<CsScore>([\s\S]*?)<\/CsScore>/);
|
||||||
|
|
||||||
|
if (!orcMatch || !scoMatch) {
|
||||||
|
throw new Error('Invalid CSD format. Must contain <CsInstruments> and <CsScore> sections.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const orc = orcMatch[1].trim();
|
||||||
|
const sco = scoMatch[1].trim();
|
||||||
|
|
||||||
|
this.log('Compiling orchestra...');
|
||||||
|
await this.csound.compileOrc(orc);
|
||||||
|
|
||||||
|
this.log('Reading score...');
|
||||||
|
await this.csound.readScore(sco);
|
||||||
|
|
||||||
|
this.log('Starting...');
|
||||||
|
await this.csound.start();
|
||||||
|
|
||||||
|
this.log('Performing...');
|
||||||
|
this.running = true;
|
||||||
|
await this.csound.perform();
|
||||||
|
|
||||||
|
this.log('Performance complete');
|
||||||
|
this.running = false;
|
||||||
|
} catch (error) {
|
||||||
|
this.running = false;
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Evaluation failed';
|
||||||
|
this.error(errorMsg);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async stop(): Promise<void> {
|
||||||
|
if (!this.csound || !this.running) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.csound.stop();
|
||||||
|
await this.csound.reset();
|
||||||
|
this.running = false;
|
||||||
|
this.log('Stopped');
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Failed to stop';
|
||||||
|
this.error(errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isRunning(): boolean {
|
||||||
|
return this.running;
|
||||||
|
}
|
||||||
|
|
||||||
|
isInitialized(): boolean {
|
||||||
|
return this.initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private log(message: string): void {
|
||||||
|
this.options.onMessage?.(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private error(message: string): void {
|
||||||
|
this.options.onError?.(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy(): Promise<void> {
|
||||||
|
if (this.running) {
|
||||||
|
await this.stop();
|
||||||
|
}
|
||||||
|
this.csound = null;
|
||||||
|
this.initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/lib/csound/index.ts
Normal file
4
src/lib/csound/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export { CsoundEngine } from './engine';
|
||||||
|
export type { CsoundEngineOptions } from './engine';
|
||||||
|
export { csound, csoundLogs, csoundInitialized, csoundRunning } from './store';
|
||||||
|
export type { LogEntry } from './store';
|
||||||
109
src/lib/csound/store.ts
Normal file
109
src/lib/csound/store.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { writable, derived, get } from 'svelte/store';
|
||||||
|
import { CsoundEngine } from './engine';
|
||||||
|
|
||||||
|
export interface LogEntry {
|
||||||
|
timestamp: Date;
|
||||||
|
message: string;
|
||||||
|
type: 'info' | 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CsoundState {
|
||||||
|
initialized: boolean;
|
||||||
|
running: boolean;
|
||||||
|
logs: LogEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCsoundStore() {
|
||||||
|
const initialState: CsoundState = {
|
||||||
|
initialized: false,
|
||||||
|
running: false,
|
||||||
|
logs: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const { subscribe, set, update } = writable<CsoundState>(initialState);
|
||||||
|
|
||||||
|
let engine: CsoundEngine | null = null;
|
||||||
|
|
||||||
|
function addLog(message: string, type: 'info' | 'error' = 'info') {
|
||||||
|
update(state => ({
|
||||||
|
...state,
|
||||||
|
logs: [...state.logs, { timestamp: new Date(), message, type }]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
if (engine) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
engine = new CsoundEngine({
|
||||||
|
onMessage: (msg) => addLog(msg, 'info'),
|
||||||
|
onError: (err) => addLog(err, 'error')
|
||||||
|
});
|
||||||
|
|
||||||
|
await engine.init();
|
||||||
|
|
||||||
|
update(state => ({
|
||||||
|
...state,
|
||||||
|
initialized: true
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Failed to initialize';
|
||||||
|
addLog(errorMsg, 'error');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async evaluate(code: string) {
|
||||||
|
if (!engine) {
|
||||||
|
throw new Error('CSound engine not initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
update(state => ({ ...state, running: true }));
|
||||||
|
await engine.evaluateCode(code);
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Evaluation failed';
|
||||||
|
addLog(errorMsg, 'error');
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
update(state => ({ ...state, running: false }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async stop() {
|
||||||
|
if (!engine) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await engine.stop();
|
||||||
|
update(state => ({ ...state, running: false }));
|
||||||
|
} catch (error) {
|
||||||
|
const errorMsg = error instanceof Error ? error.message : 'Stop failed';
|
||||||
|
addLog(errorMsg, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearLogs() {
|
||||||
|
update(state => ({
|
||||||
|
...state,
|
||||||
|
logs: []
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
async destroy() {
|
||||||
|
if (engine) {
|
||||||
|
await engine.destroy();
|
||||||
|
engine = null;
|
||||||
|
}
|
||||||
|
set(initialState);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const csound = createCsoundStore();
|
||||||
|
|
||||||
|
export const csoundLogs = derived(csound, $csound => $csound.logs);
|
||||||
|
export const csoundInitialized = derived(csound, $csound => $csound.initialized);
|
||||||
|
export const csoundRunning = derived(csound, $csound => $csound.running);
|
||||||
Reference in New Issue
Block a user