<commit_before>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 */


// Setup a single global AudioContext object
var CSOUND_AUDIO_CONTEXT = CSOUND_AUDIO_CONTEXT || 
    (function() {
        try {
            var AudioContext = window.AudioContext || window.webkitAudioContext;
            return new AudioContext();  
        }
        catch(error) {

            console.log('Web Audio API is not supported in this browser');
        }
        return null;
    }());


// Global singleton variables
var AudioWorkletGlobalScope = AudioWorkletGlobalScope || {};
var CSOUND;

/** This E6 class is used to setup scripts and
    allow the creation of new CsoundScriptProcessorNode objects
    *  @hideconstructor
    */
class CsoundScriptProcessorNodeFactory {

    // Utility function to load a script and set callback
    static loadScript(src, callback) {
        var script = document.createElement('script');
        script.src = src;
        script.onload = callback;
        document.head.appendChild(script);
    }

    /** 
     * This static method is used to asynchronously setup scripts for 
     *  ScriptProcessorNode Csound
     *
     * @param {string} script_base A string containing the base path to scripts
     */
    static importScripts(script_base='./') {
        return new Promise((resolve) => {
            CsoundScriptProcessorNodeFactory.loadScript(script_base + 'libcsound.js', () => {
                AudioWorkletGlobalScope.WAM = {}
                let WAM = AudioWorkletGlobalScope.WAM;

                WAM["ENVIRONMENT"] = "WEB";
                WAM["print"] = (t) => console.log(t);
                WAM["printErr"] = (t) => console.log(t);
                WAM["locateFile"] = (f) => script_base + f;

                AudioWorkletGlobalScope.libcsound(WAM).then(() => {

                    // Cache cwrap functions into CSOUND global object 
                    CSOUND = {
                        new: WAM.cwrap('CsoundObj_new', ['number'], null),
                        compileCSD: WAM.cwrap('CsoundObj_compileCSD', ['number'], ['number', 'string']),
                        evaluateCode: WAM.cwrap('CsoundObj_evaluateCode', ['number'], ['number', 'string']),
                        readScore: WAM.cwrap('CsoundObj_readScore', ['number'], ['number', 'string']),
                        reset: WAM.cwrap('CsoundObj_reset', null, ['number']),
                        getOutputBuffer: WAM.cwrap('CsoundObj_getOutputBuffer', ['number'], ['number']),
                        getInputBuffer: WAM.cwrap('CsoundObj_getInputBuffer', ['number'], ['number']),
                        getControlChannel: WAM.cwrap('CsoundObj_getControlChannel', ['number'], ['number', 'string']),
                        setControlChannel: WAM.cwrap('CsoundObj_setControlChannel', null, ['number', 'string', 'number']),
                        setStringChannel: WAM.cwrap('CsoundObj_setStringChannel', null, ['number', 'string', 'string']),
                        getKsmps: WAM.cwrap('CsoundObj_getKsmps', ['number'], ['number']),
                        performKsmps: WAM.cwrap('CsoundObj_performKsmps', ['number'], ['number']),
                        render: WAM.cwrap('CsoundObj_render', null, ['number']),
                        getInputChannelCount: WAM.cwrap('CsoundObj_getInputChannelCount', ['number'], ['number']),
                        getOutputChannelCount: WAM.cwrap('CsoundObj_getOutputChannelCount', ['number'], ['number']),
                        getTableLength: WAM.cwrap('CsoundObj_getTableLength', ['number'], ['number', 'number']),
                        getTable: WAM.cwrap('CsoundObj_getTable', ['number'], ['number', 'number']),
                        getZerodBFS: WAM.cwrap('CsoundObj_getZerodBFS', ['number'], ['number']),
                        setMidiCallbacks: WAM.cwrap('CsoundObj_setMidiCallbacks', null, ['number']),
                        pushMidiMessage: WAM.cwrap('CsoundObj_pushMidiMessage', null, ['number', 'number', 'number', 'number']),
                        setOutputChannelCallback: WAM.cwrap('CsoundObj_setOutputChannelCallback', null, ['number', 'number']),
                        compileOrc: WAM.cwrap('CsoundObj_compileOrc', 'number', ['number', 'string']),
                        setOption: WAM.cwrap('CsoundObj_setOption', null, ['number', 'string']),
                        prepareRT: WAM.cwrap('CsoundObj_prepareRT', null, ['number']),
                        getScoreTime: WAM.cwrap('CsoundObj_getScoreTime', null, ['number']),
                        setTable: WAM.cwrap('CsoundObj_setTable', null, ['number', 'number', 'number', 'number']),
                        destroy: WAM.cwrap('CsoundObj_destroy', null, ['number'])
                    }

                    resolve();
                }) 
            }) 
        });
    }

    /** 
     * This static method creates a new CsoundScriptProcessorNode. 
     *  @param {number} inputChannelCount Number of input channels
     *  @param {number} outputChannelCount Number of output channels
     *  @returns {object} A new CsoundScriptProcessorNode
     */
    static createNode(inputChannelCount=1, outputChannelCount=2) {
        var options = {};
        options.numberOfInputs  = inputChannelCount;
        options.numberOfOutputs  = outputChannelCount;
        return new CsoundScriptProcessorNode(CSOUND_AUDIO_CONTEXT, options);
    }
}

/**  @classdesc A ScriptProcessorNode class containing a Csound engine
 *   @class CsoundScriptProcessorNode
 *   @mixes CsoundMixin
 *   @param {AudioContext} context AudioContext in which this node will run
 *   @param {object} options Configuration options, holding numberOfInputs,
 *   numberOfOutputs
*/
CsoundScriptProcessorNode  = function(context, options) {
    var spn = context.createScriptProcessor(0, options.numberOfInputs, options.numberOfOutputs);
    spn.inputCount = options.numberOfInputs;
    spn.outputCount = options.numberOfOutputs;

    let cs = CSOUND.new();
    CSOUND.setMidiCallbacks(cs);
    CSOUND.setOption(cs, "-odac");
    CSOUND.setOption(cs, "-iadc");
    CSOUND.setOption(cs, "-M0");
    CSOUND.setOption(cs, "-+rtaudio=null");
    CSOUND.setOption(cs, "-+rtmidi=null");
    CSOUND.prepareRT(cs);
    var sampleRate = CSOUND_AUDIO_CONTEXT.sampleRate;
    CSOUND.setOption(cs, "--sample-rate="+sampleRate);
    CSOUND.setOption(cs, "--nchnls=" + this.nchnls);
    CSOUND.setOption(cs, "--nchnls_i=" + this.nchnls_i); 

    /**  
     *   @mixin CsoundMixin
     *   @ignore
     */
    let CsoundMixin = {
        csound: cs,
        compiled: false,
        msgCallback: (t) => console.log(t),
        csoundRunning: false,
        csoundOutputBuffer: null,
        csoundInputBuffer: null,
        zerodBFS: 1.0,
        offset: 32,
        ksmps: 32,
        running: false,
        started: false,
        cnt: 0,
        res: 0,
        nchnls_i: options.numberOfInputs, 
        nchnls: options.numberOfOutputs,         

        /** 
         *
         *  Writes data to a file in the WASM filesystem for
         *  use with csound.
         *
         * @param {string} filePath A string containing the path to write to.
         * @param {blob}   blobData The data to write to file.
         * @memberof CsoundMixin
         */ 
        writeToFS(filePath, blobData) {
            let FS = WAM["FS"];
            let stream = FS.open(filePath, 'w+');
            let buf = new Uint8Array(blobData)
            FS.write(stream, buf, 0, buf.length, 0);
            FS.close(stream);
        },
        
        /** Compiles a CSD, which may be given as a filename in the
         *  WASM filesystem or a string containing the code
         *
         * @param {string} csd A string containing the CSD filename or the CSD code.
         * @memberof CsoundMixin
         */ 
        compileCSD(csd) {
            CSOUND.prepareRT(this.csound);
            CSOUND.compileCSD(this.csound, csd);
            this.compiled = true;
        },

        /** Compiles Csound orchestra code.
         *
         * @param {string} orcString A string containing the orchestra code.
         * @memberof CsoundMixin
         */  
        compileOrc(orcString) {
            CSOUND.prepareRT(this.csound);
            CSOUND.compileOrc(this.csound, orcString);
            this.compiled = true;
        },

        /** Sets a Csound engine option (flag)
         *  
         *
         * @param {string} option The Csound engine option to set. This should
         * not contain any whitespace.
         * @memberof CsoundMixin
         */  
        setOption(option) {
            CSOUND.setOption(this.csound, option);
        },

        /** Renders a CSD, which may be given as a filename in the
         *  WASM filesystem or a string containing the code. This is used for
         *  disk rendering only.
         * @param {string} csd A string containing the CSD filename or the CSD code.
         * @memberof CsoundMixin
         */ 
        render(csd) {
            CSOUND.compileCSD(this.csound, csd);
            CSOUND.render(this.csound);
            this.compiled = false;
        },

        /** Evaluates Csound orchestra code.
         *
         * @param {string} codeString A string containing the orchestra code.
         * @memberof CsoundMixin
         */  
        evaluateCode(codeString) {
            CSOUND.evaluateCode(this.csound, codeString);
        },
        /** Reads a numeric score string.
         *
         * @param {string} scoreString A string containing a numeric score.
         * @memberof CsoundMixin
         */   
        readScore(scoreString) {
            CSOUND.readScore(this.csound, scoreString);
        },
        
        /** Sets the value of a control channel in the software bus
         *
         * @param {string} channelName A string containing the channel name.
         * @param {number} value The value to be set.
         * @memberof CsoundMixin
         */ 
        setControlChannel(channelName, value) {
            CSOUND.setControlChannel(this.csound, channelName, value);
        },
        
        /** Sets the value of a string channel in the software bus
         *
         * @param {string} channelName A string containing the channel name.
         * @param {string} stringValue The string to be set.
         * @memberof CsoundMixin
         */ 
        setStringChannel(channelName, value) {
            CSOUND.setStringChannel(this.csound, channelName, value); 
        },
        
        /** Starts processing in this node
         *  @memberof CsoundMixin
         */ 
        start() {
            if(this.started == false) {
                let ksmps = CSOUND.getKsmps(this.csound);
                this.ksmps = ksmps;
                this.cnt = ksmps;

                let outputPointer = CSOUND.getOutputBuffer(this.csound);
                this.csoundOutputBuffer = new Float32Array(WAM.HEAP8.buffer, outputPointer, ksmps * this.nchnls);
                let inputPointer = CSOUND.getInputBuffer(this.csound);
                this.csoundInputBuffer = new Float32Array(WAM.HEAP8.buffer, inputPointer, ksmps * this.nchnls_i);
                this.zerodBFS = CSOUND.getZerodBFS(this.csound);
                this.started = true;<commit_msg>implemented get channel in SPN<commit_after>/*
 * C S O U N D
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 */


// Setup a single global AudioContext object
var CSOUND_AUDIO_CONTEXT = CSOUND_AUDIO_CONTEXT || 
    (function() {
        try {
            var AudioContext = window.AudioContext || window.webkitAudioContext;
            return new AudioContext();  
        }
        catch(error) {

            console.log('Web Audio API is not supported in this browser');
        }
        return null;
    }());


// Global singleton variables
var AudioWorkletGlobalScope = AudioWorkletGlobalScope || {};
var CSOUND;

/** This E6 class is used to setup scripts and
    allow the creation of new CsoundScriptProcessorNode objects
    *  @hideconstructor
    */
class CsoundScriptProcessorNodeFactory {

    // Utility function to load a script and set callback
    static loadScript(src, callback) {
        var script = document.createElement('script');
        script.src = src;
        script.onload = callback;
        document.head.appendChild(script);
    }

    /** 
     * This static method is used to asynchronously setup scripts for 
     *  ScriptProcessorNode Csound
     *
     * @param {string} script_base A string containing the base path to scripts
     */
    static importScripts(script_base='./') {
        return new Promise((resolve) => {
            CsoundScriptProcessorNodeFactory.loadScript(script_base + 'libcsound.js', () => {
                AudioWorkletGlobalScope.WAM = {}
                let WAM = AudioWorkletGlobalScope.WAM;

                WAM["ENVIRONMENT"] = "WEB";
                WAM["print"] = (t) => console.log(t);
                WAM["printErr"] = (t) => console.log(t);
                WAM["locateFile"] = (f) => script_base + f;

                AudioWorkletGlobalScope.libcsound(WAM).then(() => {

                    // Cache cwrap functions into CSOUND global object 
                    CSOUND = {
                        new: WAM.cwrap('CsoundObj_new', ['number'], null),
                        compileCSD: WAM.cwrap('CsoundObj_compileCSD', ['number'], ['number', 'string']),
                        evaluateCode: WAM.cwrap('CsoundObj_evaluateCode', ['number'], ['number', 'string']),
                        readScore: WAM.cwrap('CsoundObj_readScore', ['number'], ['number', 'string']),
                        reset: WAM.cwrap('CsoundObj_reset', null, ['number']),
                        getOutputBuffer: WAM.cwrap('CsoundObj_getOutputBuffer', ['number'], ['number']),
                        getInputBuffer: WAM.cwrap('CsoundObj_getInputBuffer', ['number'], ['number']),
                        getControlChannel: WAM.cwrap('CsoundObj_getControlChannel', ['number'], ['number', 'string']),
                        setControlChannel: WAM.cwrap('CsoundObj_setControlChannel', null, ['number', 'string', 'number']),
                        setStringChannel: WAM.cwrap('CsoundObj_setStringChannel', null, ['number', 'string', 'string']),
                        getKsmps: WAM.cwrap('CsoundObj_getKsmps', ['number'], ['number']),
                        performKsmps: WAM.cwrap('CsoundObj_performKsmps', ['number'], ['number']),
                        render: WAM.cwrap('CsoundObj_render', null, ['number']),
                        getInputChannelCount: WAM.cwrap('CsoundObj_getInputChannelCount', ['number'], ['number']),
                        getOutputChannelCount: WAM.cwrap('CsoundObj_getOutputChannelCount', ['number'], ['number']),
                        getTableLength: WAM.cwrap('CsoundObj_getTableLength', ['number'], ['number', 'number']),
                        getTable: WAM.cwrap('CsoundObj_getTable', ['number'], ['number', 'number']),
                        getZerodBFS: WAM.cwrap('CsoundObj_getZerodBFS', ['number'], ['number']),
                        setMidiCallbacks: WAM.cwrap('CsoundObj_setMidiCallbacks', null, ['number']),
                        pushMidiMessage: WAM.cwrap('CsoundObj_pushMidiMessage', null, ['number', 'number', 'number', 'number']),
                        setOutputChannelCallback: WAM.cwrap('CsoundObj_setOutputChannelCallback', null, ['number', 'number']),
                        compileOrc: WAM.cwrap('CsoundObj_compileOrc', 'number', ['number', 'string']),
                        setOption: WAM.cwrap('CsoundObj_setOption', null, ['number', 'string']),
                        prepareRT: WAM.cwrap('CsoundObj_prepareRT', null, ['number']),
                        getScoreTime: WAM.cwrap('CsoundObj_getScoreTime', null, ['number']),
                        setTable: WAM.cwrap('CsoundObj_setTable', null, ['number', 'number', 'number', 'number']),
                        destroy: WAM.cwrap('CsoundObj_destroy', null, ['number'])
                    }

                    resolve();
                }) 
            }) 
        });
    }

    /** 
     * This static method creates a new CsoundScriptProcessorNode. 
     *  @param {number} inputChannelCount Number of input channels
     *  @param {number} outputChannelCount Number of output channels
     *  @returns {object} A new CsoundScriptProcessorNode
     */
    static createNode(inputChannelCount=1, outputChannelCount=2) {
        var options = {};
        options.numberOfInputs  = inputChannelCount;
        options.numberOfOutputs  = outputChannelCount;
        return new CsoundScriptProcessorNode(CSOUND_AUDIO_CONTEXT, options);
    }
}

/**  @classdesc A ScriptProcessorNode class containing a Csound engine
 *   @class CsoundScriptProcessorNode
 *   @mixes CsoundMixin
 *   @param {AudioContext} context AudioContext in which this node will run
 *   @param {object} options Configuration options, holding numberOfInputs,
 *   numberOfOutputs
 *   @returns {object} A new CsoundScriptProcessorNode
 */
CsoundScriptProcessorNode  = function(context, options) {
    var spn = context.createScriptProcessor(0, options.numberOfInputs, options.numberOfOutputs);
    spn.inputCount = options.numberOfInputs;
    spn.outputCount = options.numberOfOutputs;

    let cs = CSOUND.new();
    CSOUND.setMidiCallbacks(cs);
    CSOUND.setOption(cs, "-odac");
    CSOUND.setOption(cs, "-iadc");
    CSOUND.setOption(cs, "-M0");
    CSOUND.setOption(cs, "-+rtaudio=null");
    CSOUND.setOption(cs, "-+rtmidi=null");
    CSOUND.prepareRT(cs);
    var sampleRate = CSOUND_AUDIO_CONTEXT.sampleRate;
    CSOUND.setOption(cs, "--sample-rate="+sampleRate);
    CSOUND.setOption(cs, "--nchnls=" + this.nchnls);
    CSOUND.setOption(cs, "--nchnls_i=" + this.nchnls_i); 

    /**  
     *   @mixin CsoundMixin
     *   @ignore
     */
    let CsoundMixin = {
        csound: cs,
        compiled: false,
        msgCallback: (t) => console.log(t),
        csoundRunning: false,
        csoundOutputBuffer: null,
        csoundInputBuffer: null,
        zerodBFS: 1.0,
        offset: 32,
        ksmps: 32,
        running: false,
        started: false,
        cnt: 0,
        res: 0,
        nchnls_i: options.numberOfInputs, 
        nchnls: options.numberOfOutputs,
        channel: {},
        channelCallback: {},
        
        /** 
         *
         *  Writes data to a file in the WASM filesystem for
         *  use with csound.
         *
         * @param {string} filePath A string containing the path to write to.
         * @param {blob}   blobData The data to write to file.
         * @memberof CsoundMixin
         */ 
        writeToFS(filePath, blobData) {
            let FS = WAM["FS"];
            let stream = FS.open(filePath, 'w+');
            let buf = new Uint8Array(blobData)
            FS.write(stream, buf, 0, buf.length, 0);
            FS.close(stream);
        },
        
        /** Compiles a CSD, which may be given as a filename in the
         *  WASM filesystem or a string containing the code
         *
         * @param {string} csd A string containing the CSD filename or the CSD code.
         * @memberof CsoundMixin
         */ 
        compileCSD(csd) {
            CSOUND.prepareRT(this.csound);
            CSOUND.compileCSD(this.csound, csd);
            this.compiled = true;
        },

        /** Compiles Csound orchestra code.
         *
         * @param {string} orcString A string containing the orchestra code.
         * @memberof CsoundMixin
         */  
        compileOrc(orcString) {
            CSOUND.prepareRT(this.csound);
            CSOUND.compileOrc(this.csound, orcString);
            this.compiled = true;
        },

        /** Sets a Csound engine option (flag)
         *  
         *
         * @param {string} option The Csound engine option to set. This should
         * not contain any whitespace.
         * @memberof CsoundMixin
         */  
        setOption(option) {
            CSOUND.setOption(this.csound, option);
        },

        /** Renders a CSD, which may be given as a filename in the
         *  WASM filesystem or a string containing the code. This is used for
         *  disk rendering only.
         * @param {string} csd A string containing the CSD filename or the CSD code.
         * @memberof CsoundMixin
         */ 
        render(csd) {
            CSOUND.compileCSD(this.csound, csd);
            CSOUND.render(this.csound);
            this.compiled = false;
        },

        /** Evaluates Csound orchestra code.
         *
         * @param {string} codeString A string containing the orchestra code.
         * @memberof CsoundMixin
         */  
        evaluateCode(codeString) {
            CSOUND.evaluateCode(this.csound, codeString);
        },
        /** Reads a numeric score string.
         *
         * @param {string} scoreString A string containing a numeric score.
         * @memberof CsoundMixin
         */   
        readScore(scoreString) {
            CSOUND.readScore(this.csound, scoreString);
        },
        
        /** Sets the value of a control channel in the software bus
         *
         * @param {string} channelName A string containing the channel name.
         * @param {number} value The value to be set.
         * @memberof CsoundMixin
         */ 
        setControlChannel(channelName, value) {
            CSOUND.setControlChannel(this.csound, channelName, value);
        },
        
        /** Sets the value of a string channel in the software bus
         *
         * @param {string} channelName A string containing the channel name.
         * @param {string} stringValue The string to be set.
         * @memberof CsoundMixin
         */ 
        setStringChannel(channelName, value) {
            CSOUND.setStringChannel(this.csound, channelName, value); 
        },

        /** Request the data from a control channel 
         *
         * @param {string} channelName A string containing the channel name.
         * @param {function} callback An optional callback to be called when
         *  the requested data is available. This can be set once for all
         *  subsequent requests.
         */ 
        requestControlChannel(channelName, callback = null) {
            this.channel[channelName] = CSOUND.getControlChannel(this.csound, channelName);
            if (callback !== null)
                this.channelCallback[channelName] = callback;
            if (typeof this.channelCallback[channelName] !== 'undefined')
                this.channelCallback[channelName]();   
        },

        /** Get the latest requested channel data 
         *
         * @param {string} channelName A string containing the channel name.
         * @returns {(number|string)} The latest channel value requested.
         */   
        getChannel(channelName) {
            return this.channel[channelName];
        },

        
        /** Starts processing in this node
         *  @memberof CsoundMixin
         */ 
        start() {
            if(this.started == false) {
                let ksmps = CSOUND.getKsmps(this.csound);
                this.ksmps = ksmps;
                this.cnt = ksmps;

                let outputPointer = CSOUND.getOutputBuffer(this.csound);
                this.csoundOutputBuffer = new Float32Array(WAM.HEAP8.buffer, outputPointer, ksmps * this.nchnls);
                let inputPointer = CSOUND.getInputBuffer(this.csound);
                this.csoundInputBuffer = new Float32Array(WAM.HEAP8.buffer, inputPointer, ksmps * this.nchnls_i);
                this.zerodBFS = CSOUND.getZerodBFS(this.csound);
                this.started = true;
{'fraction_non_alphanumeric': 0.10931009204202981, 'fraction_numerical': 0.0019548749694550784, 'mean_word_length': 2.098031794095382, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3302299', 'n_tokens_mistral': 7031, 'n_tokens_neox': 6725, 'n_words': 1745}