nwhetsell / csound-api

Node.js bindings to Csound’s API
https://www.npmjs.com/package/csound-api
MIT License
32 stars 6 forks source link

Stopping/Resetting an instance of PerformAsync causes crash #5

Closed hlolli closed 7 years ago

hlolli commented 7 years ago

As I'm running this API on clojurescript I'm not sure if a reproduceable code makes much sense. But no matter how I try, restarting csound instance is impossible. The nodejs repl becomes unresponsive after stopping, resetting, destroyng ore cleanup-ing a csound instance. Maybe a special function to stop PerformAsync would make sense as I'm assumeing that in the c# code it's a pointer to a concurrent function? (where some signal within that function would stop the concurrent loop).

nwhetsell commented 7 years ago

Some kind of test case may be necessary to help resolve this issue. Running in Node.js a JavaScript file containing

const csound = require('csound-api');
const Csound = csound.Create();
const orchestra = `
  0dbfs = 1
  instr SawtoothSweep
    outc vco2(0.5 * 0dbfs, expseg(110, 1, 220, 1, 110))
  endin
`;
const score = `
  i "SawtoothSweep" 0 2
  e
`;

csound.SetOption(Csound, '--output=dac');
csound.CompileOrc(Csound, orchestra);
csound.ReadScore(Csound, score);

if (csound.Start(Csound) === csound.SUCCESS) {
  console.log('\n==> Starting first performance...\n');
  csound.PerformAsync(Csound, result => {
    console.log(`\n==> First performance stopped with result ${result}\n`);

    csound.Reset(Csound);

    csound.SetOption(Csound, '--output=dac');
    csound.CompileOrc(Csound, orchestra);
    csound.ReadScore(Csound, score);

    if (csound.Start(Csound) === csound.SUCCESS) {
      console.log('\n==> Starting second performance...\n');
      csound.PerformAsync(Csound, result => {
        console.log(`\n==> Second performance stopped with result ${result}\n`);
        csound.Destroy(Csound);
      });
    }
  });

  // This stops the first performance after about one second.
  setTimeout(() => csound.Stop(Csound), 1000);
}

should result in two performances of the same orchestra and score (based on this example). The second performance begins after stopping and resetting an instance of Csound. When I run that script in Node.js 7.5.0 on macOS 10.12.3, I get the expected result (I’ve included Csound’s output below). What happens when you run that script in Node.js?

There shouldn’t be a need for a function to stop csound.PerformAsync; csound.Stop should do this already. Also, note that this Addon is written in C++, not C#.

Here is Csound’s output when I run the above script:

virtual_keyboard real time MIDI plugin for Csound
WARNING: STK opcodes not available: define environment variable RAWWAVE_PATH
(points to rawwaves directory) to use STK opcodes.
0dBFS level = 32768.0
--Csound version 6.08 (double samples) Nov 23 2016 
[commit: a1159a1e12a1095c4607f7162c44b196f5143959]
libsndfile-1.0.25
instr SawtoothSweep uses instrument number 1
WARNING: STK opcodes not available: define environment variable RAWWAVE_PATH
(points to rawwaves directory) to use STK opcodes.
rtaudio: PortAudio module enabled ... 
using callback interface
rtmidi: PortMIDI module enabled
graphics suppressed, ascii substituted
0dBFS level = 1.0
orch now loaded
audio buffered in 1024 sample-frame blocks
PortAudio V19-devel (built Feb 12 2010 09:42:54)
   0: dac0 (Built-in Output)
PortAudio: selected output device 'Built-in Output'
writing 1024 sample blks of 64-bit floats to dac 
SECTION 1:

==> Starting first performance...

new alloc for instr SawtoothSweep:
csoundPerform(): stopped.

==> First performance stopped with result 0

resetting Csound instance
inactive allocs returned to freespace
end of score.          overall amps:  0.58529
       overall samples out of range:        0
0 errors in performance
Elapsed time at end of performance: real: 1.074s, CPU: 0.053s
closing device
38 1024 sample blks of 64-bit floats written to dac
virtual_keyboard real time MIDI plugin for Csound
WARNING: STK opcodes not available: define environment variable RAWWAVE_PATH
(points to rawwaves directory) to use STK opcodes.
0dBFS level = 32768.0
--Csound version 6.08 (double samples) Nov 23 2016 
[commit: a1159a1e12a1095c4607f7162c44b196f5143959]
libsndfile-1.0.25
instr SawtoothSweep uses instrument number 1
WARNING: STK opcodes not available: define environment variable RAWWAVE_PATH
(points to rawwaves directory) to use STK opcodes.
rtaudio: PortAudio module enabled ... 
using callback interface
rtmidi: PortMIDI module enabled
0dBFS level = 1.0
orch now loaded
audio buffered in 1024 sample-frame blocks
PortAudio V19-devel (built Feb 12 2010 09:42:54)
   0: dac0 (Built-in Output)
PortAudio: selected output device 'Built-in Output'
writing 1024 sample blks of 64-bit floats to dac 
SECTION 1:

==> Starting second performance...

new alloc for instr SawtoothSweep:
B  0.000 ..  2.000 T  2.000 TT  2.000 M:  0.58539
Score finished in csoundPerform().

==> Second performance stopped with result 2

inactive allocs returned to freespace
end of score.          overall amps:  0.58539
       overall samples out of range:        0
0 errors in performance
Elapsed time at end of performance: real: 2.002s, CPU: 0.020s
closing device
87 1024 sample blks of 64-bit floats written to dac
hlolli commented 7 years ago

Your script seems to work fine on node.js, I had the theory that the performance had to end, so I tried adding an 'e' inputmessage to end the performance, I get the same error as with all the others. Not sure if this is clojurescript specific problem, only reason I'm not sure is that I recently had similar problem with csound-api on elisp.

Steps to reproduce (with the big impediment that it's on cljs)

(def csound ((js* "require") "csound-api"))
      (def Csound (.Create csound))
      (.SetOption csound Csound "-odac")
      (.SetOption csound Csound "-+rtaudio=alsa")
      (.CompileOrc csound Csound (str some-instrument)) 
      (.Start csound Csound)
      (.PerformAsync csound Csound)
;; After a while
      (.InputMessage csound Csound "e")
;; After .PerformAsync
 0dBFS level = 32768.0
--Csound version 6.09 (double samples) Feb 11 2017 
[commit: 1d1375ae405709a38d66d7932988dd7847ef1958]
libsndfile-1.0.27
Reading options from $HOME/.csound6rc
rtaudio: ALSA module enabled
rtmidi: ALSA Raw MIDI module enabled
graphics suppressed, ascii substituted
0dBFS level = 1.0
orch now loaded
audio buffered in 256 sample-frame blocks
ALSA output: total buffer size: 1024, period size: 256 
writing 512 sample blks of 64-bit floats to dac 
SECTION 1:
;; after (.InputMessage csound Csound "e")
Score finished in csoundPerform().
undefined:0

TypeError: undefined is not a function
inactive allocs returned to freespace
end of score.          overall amps:  0.00000  0.00000
       overall samples out of range:        0        0
0 errors in performance
Elapsed time at end of performance: real: 20.879s, CPU: 0.243s
WARNING: Buffer underrun in real-time audio output
1623 512 sample blks of 64-bit floats written to dac

At this point the nodejs-repl is blocked. Need to research, I try tonight to rule out if it's cljs specific problem.

hlolli commented 7 years ago

That was quick, I'm not used to being denied static errors, but I must get myself comfortable with it :)

(.PerformAsync csound Csound
                     (fn [] (.Stop csound Csound)))

.PerformAsync needs the second argument to be a function. Now this works and I must say this makes a lot of sense.