Flexible reading back

Hi all,
i am trying to build a generic midi data recorder and midi player.
In the first instrument, these midi data are written to a text file in packages of 4: status (for example: controller only = 176), midi channel, CC number and value.
Then, in a second instrument that plays back the midi data, this playback should be flexible in its playback speed. And this is the issue that i do not know how to solve…

Right now, my code is not really using real midi data, but mimicking it. When this flexible issue is resolved, i can then move on and add the midi input ports and record different controller numbers etc.

This is my code:

<CsoundSynthesizer>
<CsOptions>
; Select audio/midi flags here according to platform
-odac     ;--displays ;;;realtime audio out
;-iadc    ;;;uncomment -iadc if realtime audio input is needed too
; For Non-realtime ouput leave only the line below:
; -o gen02.wav -W ;;; for file output any platform
</CsOptions>
<CsInstruments>

sr = 48000 
ksmps = 128 
nchnls = 2 
0dbfs  = 1 

giFt ftgen  0, 0, kr*4, -2, 0                       ; kr = 375
giFtable ftgen  0, 0, kr*4, -2, 0
seed 0

instr 1 ; mimic CC midi controller

kndx init 0
;kndx     linseg    0, 1, ftlen(giFt)                ; move through table in 1 second
kvalue  linseg  100, p3*.5, 0, p3 *.5, 100          ; 100 Hz, back to 0, up to 100
kstatus =   176                                     ; CC
kchan   =   1                                       ; midi channel 1
kCC     =   7                                       ; controller 7

tablew kstatus, kndx, giFt                          ; load CC
tablew kchan, kndx+1, giFt                          ; load midi channel
tablew kCC, kndx+2, giFt                            ; load controller 7
tablew int(kvalue), kndx+3, giFt                    ; value 0 - 127
kndx += 4
ares poscil3 .5, 100+int(kvalue)                    ; sine, add 100Hz and back down
outs ares, ares

krel    release                                     ; write in last k cycle
if (krel == 1) then
    ftsavek "/home/menno/MidiData2.txt", 1, 1, giFt  ; write as text file to disk (k rate)
endif
endin

instr 2 ; play back

ftload "/home/menno/MidiData2.txt", 1, giFtable      ; load textfile in new table (i rate)
kndx init 0
;kval0 table3  kndx, giFtable
;kval1 table3  kndx+1, giFtable
;kval2 table3  kndx+2, giFtable
kval3 table3  kndx+3, giFtable                       ; use only these values in vco2

;printsk    "status = %d     channel = %d    controller = %d  value = %d\n", kval0, kval1, kval2, kval3

printk2 kval3

ares vco2 .3, 100+(kval3)                           ; saw, add 100Hz and back down
outs ares, ares
kndx += 4
endin
</CsInstruments>
<CsScore>

i1 0 1 1     ; 1 sec.
i2 2 1 1     ; 1 sec, as recorded
i2 4 2 .5     ; trying to stretch 2 x ....
e
</CsScore>
</CsoundSynthesizer>

What happens now is that only the changing value of every 4th index is read; the changing value of the controller 7. How can i influence the speed of the reading back of the file, relative to p3?

hi menno -

if i get it right, you want to record signals in real-time which you
then want to play back say twice as slow.

if this is correct, i think it is very hard to to with one table which
holds four different signals. because:

when you have one signal in one table, you can just ready more slow, or
fast, and interpolate between the values.

but if you have four signals in one table, you cannot, because you have
to interpolate between index 0 and 4 in ignoring index 1-3.

perhaps others find a solution, but i’d recommend to either write in
four tables, or split the interpolating table in four when you read it.

joachim

thanks, Joachim, this feedback is welcome and challenging.
I see your point in having several tables, so one can later choose which one to do the interpolation on.
If i were to record 3 different controllers (7, 8, 9 for example) that would mean writing 3 (x 4 midi data sets) files. Or, alternatively, write 3 files with the 4 midi data sets, and later when reading, splitting those up to 3 x 4 =12 files at i rate. Or perhaps in memory only?

Once in memory, the interpolation can begin when reading them at k-rate.

Nice puzzle this one.
(It also shows that the Csound Midi system is not a very developed one. I am so used to programs like Reaper and Cubase that i take all for granted how this is organized. )

This is true. Cabbage has its own MIDI file reading opcode that lets you read a MIDI file from disk at various speeds. I initially looked at writing them with portmidi but it looked like too much work. In the end I just used JUCE. The code is pretty simple though and could be ported to a standalone plugin opcode.

Understandable that you choose the most “easy” way out: the MIDI file reading through JUCE.
But it is a pity that the Midi situation is not attacked at the most basic level, in Csound itself.
On the other hand, i do see the lack of developers and the ones that do develop Csound, are already working hard…

Opcodes like:
midirecord
and
midiplay
…of course, MIDI2 compatible :grin: