NULL pointer access error when accessing in/out csound buffer in Python

Dear Csounders!

I’m getting this NULL pointer access error when trying to get pointer from input or output buffer of a compiled csound object. Python script that I use is the following one:

import ctcsound as csound
import numpy as np


cs = csound.Csound()
cs.compileCsd("bufferInOut.csd")
ibuf = cs.inputBuffer()
obuf = cs.outputBuffer()
cs.start()

while not cs.performBuffer():
    assert(np.array_equal(obuf, ibuf / 3.0))

cs.reset()
del cs

CSD file is this one: ctcsound/bufferInOut.csd at master · csound/ctcsound · GitHub

I’m working with python3 and csound 6.16. I have tested this with python versions 3.7 and 3.9 and on windows 10 and MacOS 12.4.0 and the error is the same. And so far I’ve seen everything else regarding to ctcsound is working correctly. I can normally compile csd file and play it.

More detailed error:

File "c:\Projects\csound_stuff\python\test_csound_io.py", line 7, in <module> 
    ibuf = cs.inputBuffer()
File "C:\Program Files\Csound6_x64\bin\ctcsound.py", line 1215, in inputBuffer
    return arrFromPointer(p)
File "C:\Program Files\Csound6_x64\bin\ctcsound.py", line 37, in <lambda>
    arrFromPointer = lambda p : p.contents
File "C:\Users\lovre\.conda\envs\csound_env\lib\site-packages\numpy\ctypeslib.py", line 219, in contents
    buffer = ctypes.cast(self, ctypes.POINTER(full_ctype)).contents
ValueError: NULL pointer access

Is there a specific numpy version that I need to use or something else that I need to configure before trying to access IO buffers?

Best regards,
Lovre

So it looks that when csound file is compiled with compileCsd function, there is no direct access to the csound’s IO buffers. On the other hand if csound file is compiled with compile_ function one can access IO buffers normally.

compileCsd function calls csoundCompileCsd c-function and compile_ calls csoundCompile c-function.
Is it possible that this is a bug? :thinking:

An excellent example of how to test Csound’s inputs and outputs is given here: ctcsound/test_ctcsound.py at master · csound/ctcsound · GitHub

Here is also my example that gives more control regarding input values and speed of execution. Note that this example is an illustrative example and not a performant one :wink:

import ctcsound
cs = ctcsound.Csound()
cs.compile_("csound", "bufferInOut_test.csd")
ibuf = cs.spin()
obuf = cs.spout()
nchnls = cs.nchnls()
num_of_frames = int(len(ibuf)/nchnls)

cntr = 0
# write new values
for frame_index in range(num_of_frames):
    for chanel_index in range(nchnls):
        ibuf[frame_index*nchnls + chanel_index] = cntr
        cntr += 1

while not cs.performKsmps():
    # check old values
    for frame_index in range(num_of_frames):
        for chanel_index in range(nchnls):
            expected_value = cntr - len(ibuf) + frame_index*nchnls + chanel_index
            if obuf[frame_index*nchnls + chanel_index] != expected_value:
                print(f'Error: Expected value: {expected_value} doesnt match received one: {obuf[frame_index + chanel_index]}')
    
    # write new values
    for frame_index in range(num_of_frames):
        for chanel_index in range(nchnls):
            ibuf[frame_index*nchnls + chanel_index] = cntr
            cntr += 1

cs.reset()
del cs

Associated .csd file:

<CsoundSynthesizer>
<CsOptions>
  -n
</CsOptions>

<CsInstruments>
sr     = 1024
ksmps  = 128
nchnls = 2
; 0dbfs  = 1  ; so that we can write integers into IO buffers

instr 1
  aIn[] init nchnls 
  aOut[] init nchnls 

  aIn in
  aOut = aIn
  out aOut
endin
</CsInstruments>

<CsScore>
i 1 0 5
e
</CsScore>
</CsoundSynthesizer>