aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/1-sqlite-basic.csd41
-rw-r--r--examples/2-sqlite-krate.csd95
-rw-r--r--examples/3-postgresql-basic.csd100
-rw-r--r--examples/4-postgresql-analysis.csd104
-rw-r--r--examples/5-mysql-basic.csd110
-rw-r--r--examples/6-mysql-randomnotes.csd99
-rw-r--r--examples/7-violsqlite.csd172
-rw-r--r--examples/sounds/violin.wavbin0 -> 586448 bytes
-rw-r--r--examples/toCheck/7-sqlite-pitchmatcher.csd140
9 files changed, 861 insertions, 0 deletions
diff --git a/examples/1-sqlite-basic.csd b/examples/1-sqlite-basic.csd
new file mode 100644
index 0000000..8177d4a
--- /dev/null
+++ b/examples/1-sqlite-basic.csd
@@ -0,0 +1,41 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 1
+
+ print some data from a sqlite3 database at i-rate
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+; sqlite3 takes a file path, or :memory: for a temporary in-memory database
+; gidb dbconnect "sqlite", "/tmp/example.db"
+gidb dbconnect "sqlite", ":memory:"
+
+instr start_example
+
+ ; print a random value
+ ires1 dbscalar gidb, "SELECT RANDOM()"
+ print ires1
+
+ ; print the second column (1) of the first row (0)
+ ires2 dbscalar gidb, "SELECT 99, 98", 0, 1
+ print ires2
+endin
+
+
+</CsInstruments>
+<CsScore>
+i "start_example" 0 1
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/2-sqlite-krate.csd b/examples/2-sqlite-krate.csd
new file mode 100644
index 0000000..d6a370f
--- /dev/null
+++ b/examples/2-sqlite-krate.csd
@@ -0,0 +1,95 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 2
+
+ Use a metro to trigger the insertion of points from a line into a sqlite database,
+ then read back the points in reverse order and play back with enveloping
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+
+; sqlite3 takes a file path, or :memory: for a temporary in-memory database
+;gidb dbconnect "sqlite", ":memory:"
+gidb dbconnect "sqlite", "/tmp/example.db"
+
+
+instr start_example
+
+ ; create the table with just one float column
+ kdone1 dbexec_k gidb, "CREATE TABLE IF NOT EXISTS frequencies (freq float)", -1
+
+ ; execute when create table statement has completed - clear out if the table does exist
+ kdone2 dbexec_k gidb, "DELETE FROM frequencies", kdone1
+
+ ; execute when delete has completed
+ schedkwhen kdone2, 0, 0, "db_insert", 0, 5
+ schedkwhen kdone2, 0, 0, "db_select", 5, 10
+
+
+endin
+
+
+; insert frequency values from line into database at k rate
+instr db_insert
+
+ ; generate some data and print
+ kfreq line 440, p3, 1000
+ ktrigger metro 5
+ printk 0.2, kfreq
+
+ ; insert snapshot with each metro (as long as the last query is still not pending)
+ Squery sprintfk "INSERT INTO frequencies (freq) VALUES (%f)", kfreq
+ kdone dbexec_k gidb, Squery, ktrigger
+
+endin
+
+
+; read frequency values from database at i rate: obtain the values in reverse order
+instr db_select
+
+ ; get all values in descending order into an array
+ ires[][] dbarray gidb, "SELECT freq FROM frequencies ORDER BY freq desc"
+ itimestep = 0.3
+ index = 0
+ itime = 0
+ ilast = 0
+
+ ; loop through the values and play the frequency with some basic interpolation between last current values
+ while (index < lenarray(ires)) do
+ if (ilast != 0) then
+ event_i "i", "playpitch", itime, itimestep, ilast, ires[index][0]
+ endif
+ ilast = ires[index][0]
+ index += 1
+ itime += itimestep * 0.8
+ od
+endin
+
+
+; basic oscillator instrument with envelope
+instr playpitch
+ ipitch1 = p4
+ ipitch2 = p5
+ kamp linseg 0, p3*0.2, 1, p3*0.6, 1, p3*0.2, 0
+ kpitch line ipitch1, p3, ipitch2
+ aout oscil 0.8, kpitch
+ outs aout*kamp, aout*kamp
+endin
+
+</CsInstruments>
+<CsScore>
+i "start_example" 0 15
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/3-postgresql-basic.csd b/examples/3-postgresql-basic.csd
new file mode 100644
index 0000000..053ee07
--- /dev/null
+++ b/examples/3-postgresql-basic.csd
@@ -0,0 +1,100 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 3
+
+ Run some queries on a PostgreSQL database using just inbuilt functions and system tables
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+
+; connect: type, hostname or IP, database name, username, password
+gidb dbconnect "postgresql", "localhost", "databasename", "username", "password"
+
+
+; print a random float from the database
+instr execscalar
+ ires dbscalar gidb, "SELECT RANDOM()"
+ print ires
+endin
+
+
+; print the current_timestamp from the database
+instr execscalarstr
+ Sres dbscalar gidb, "SELECT current_timestamp || '\n'"
+ prints Sres
+endin
+
+
+; print some float columns from the database activity statistics table
+instr execarray
+ ires[][] dbarray gidb, "SELECT datid, pid, usesysid FROM pg_stat_activity"
+ printarray ires
+endin
+
+
+; print some string columns from the database activity table
+instr execarraystr
+ Sres[][] dbarray gidb, "SELECT datname, usename, state, query_start FROM pg_stat_activity"
+ irow = 0
+
+ ; loop through as printarray does not support multidimensional string arrays
+ while (irow < lenarray(Sres)) do
+ icol = 0
+ while (icol < 3) do
+ Sitem sprintf "%d, %d : %s\n", irow, icol, Sres[irow][icol]
+ prints Sitem
+ icol += 1
+ od
+ irow += 1
+ od
+
+endin
+
+
+; print the current_timestamp from the database server twice per second, and print when the query has been executed
+instr execscalar_k
+ ktrigger metro 2
+ kdone, Sres dbscalar_k gidb, "SELECT 'now = ' || current_timestamp || '\n'", ktrigger
+ if (kdone == 1) then
+ printks "%s", 0, Sres
+ endif
+endin
+
+
+; print 2x2 random floats from the database every second
+instr execarray_k
+ ktrigger metro 1
+ kdone, kres[][] dbarray_k gidb, "SELECT RANDOM(), RANDOM() UNION SELECT RANDOM(), RANDOM()", ktrigger
+ if (kdone == 1) then
+ printk2 kres[0][0]
+ printk2 kres[0][1]
+ printk2 kres[1][0]
+ printk2 kres[1][1]
+ endif
+
+endin
+
+
+</CsInstruments>
+<CsScore>
+
+i "execscalar" 0 1
+i "execscalarstr" 2 1
+i "execarray" 4 1
+i "execarraystr" 6 1
+i "execscalar_k" 7 5
+i "execarray_k" 12 5
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/4-postgresql-analysis.csd b/examples/4-postgresql-analysis.csd
new file mode 100644
index 0000000..38a82a6
--- /dev/null
+++ b/examples/4-postgresql-analysis.csd
@@ -0,0 +1,104 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 4
+
+ Pitch track an oscillator, inserting the time, frequency and amplitude values in a PostgreSQL database
+ as fast as it will accept, at k-rate.
+ Read back the values at i-rate in the db_play instrument and create events to mimic the original oscillator.
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+
+; connect: type, hostname or IP, database name, username, password
+gidb dbconnect "postgresql", "localhost", "databasename", "username", "password"
+
+
+; create table if it doesn't exist. truncate if it does
+instr start_example
+ kdone1 dbexec_k gidb, "CREATE TABLE IF NOT EXISTS analysis (time FLOAT, rms FLOAT, freq FLOAT)", -1
+ kdone2 dbexec_k gidb, "TRUNCATE TABLE analysis", kdone1
+
+ ; schedule next steps
+ if (kdone2 == 1) then
+ schedule "db_analyse", 0, 3
+ schedule "db_play", 3.5, 3.5
+ turnoff
+ endif
+endin
+
+
+instr db_analyse
+
+ ; the oscillator
+ a1 oscil abs(oscil(1, 0.6)), linseg(440, p3*0.2, 800, p3*0.2, 220, p3*0.2, 220, p3*0.2, 350, p3*0.2, 440)
+
+ ; pitch/rms and time tracking
+ kcps, krms pitchamdf a1, 220, 800, 0, 0
+ ktime timeinsts
+
+ ; listen back to the pitch track output
+ a1 oscil krms, kcps
+
+ ; insert the time, rms and frequency values as fast as the database will accept
+ kdone init 1
+ kdone dbexec_k gidb, sprintfk("INSERT INTO analysis (time, rms, freq) VALUES (%f, %f, %f)", ktime, krms, kcps), 1
+
+ ; declick end
+ aout = a1 * linseg(1, p3*0.99, 1, p3*0.01, 0)
+ outs aout, aout
+endin
+
+
+instr db_play
+
+ ; get all of the values
+ idata[][] dbarray gidb, "SELECT time, rms, freq FROM analysis"
+
+ ; loop through
+ index = 0
+ while (index < lenarray(idata)) do
+
+ ; set the duration to be the time to the next row multiplied by an overlap
+ if (index == lenarray(idata) - 1) then
+ iduration = 1
+ else
+ iduration = (idata[index+1][0] - idata[index][0]) * 3.2
+ endif
+
+ ; create the event accordingly
+ event_i "i", "oscillator", idata[index][0]*2, iduration, idata[index][1], idata[index][2]
+ index += 1
+ od
+endin
+
+
+instr oscillator
+
+ ; basic oscillator
+ iamp = p4
+ ifreq = p5
+ a1 oscil iamp * 0.5, ifreq
+
+ ; envelope to try and take away the quantised type sound
+ aout = a1 * linseg(0, p3*0.45, 1, p3*0.1, 1, p3*0.45, 0)
+ outs aout, aout
+endin
+
+</CsInstruments>
+<CsScore>
+i "start_example" 0 7
+
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/5-mysql-basic.csd b/examples/5-mysql-basic.csd
new file mode 100644
index 0000000..bf8e857
--- /dev/null
+++ b/examples/5-mysql-basic.csd
@@ -0,0 +1,110 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 3
+
+ Run some queries on a MySQL database using just inbuilt functions and system tables
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+
+; connect: type, hostname or IP, database name, username, password
+gidb dbconnect "mysql", "hostname", "databasename", "user", "password"
+
+
+; print a random float from the database
+instr execscalar
+ ires dbscalar gidb, "SELECT RAND()"
+ print ires
+endin
+
+
+; print the current_timestamp from the database
+instr execscalarstr
+ Sres dbscalar gidb, "SELECT CONCAT(NOW(), '\n')"
+ prints Sres
+endin
+
+
+; print some float columns from the database activity statistics table
+instr execarray
+ Sql = {{
+ SELECT INDEX_LENGTH, AVG_ROW_LENGTH, TABLE_ROWS
+ FROM INFORMATION_SCHEMA.TABLES
+ LIMIT 10
+ }}
+ ires[][] dbarray gidb, Sql
+ printarray ires
+endin
+
+
+; print some string columns from the database activity table
+instr execarraystr
+ Sql = {{
+ SELECT TABLE_NAME, TABLE_COMMENT, ROW_FORMAT
+ FROM INFORMATION_SCHEMA.TABLES
+ LIMIT 10
+ }}
+ Sres[][] dbarray gidb, Sql
+ irow = 0
+
+ ; loop through as printarray does not support multidimensional string arrays
+ while (irow < lenarray(Sres)) do
+ icol = 0
+ while (icol < 3) do
+ Sitem sprintf "%d, %d : %s\n", irow, icol, Sres[irow][icol]
+ prints Sitem
+ icol += 1
+ od
+ irow += 1
+ od
+
+endin
+
+
+; print the current_timestamp from the database server twice per second, and print when the query has been executed
+instr execscalar_k
+ ktrigger metro 2
+ kdone, Sres dbscalar_k gidb, "SELECT CONCAT('now = ', NOW(), '\n')", ktrigger
+ if (kdone == 1) then
+ printks "%s", 0, Sres
+ endif
+endin
+
+
+; print 2x2 random floats from the database every second
+instr execarray_k
+ ktrigger metro 1
+ kdone, kres[][] dbarray_k gidb, "SELECT RAND(), RAND() UNION SELECT RAND(), RAND()", ktrigger
+ if (kdone == 1) then
+ printk2 kres[0][0]
+ printk2 kres[0][1]
+ printk2 kres[1][0]
+ printk2 kres[1][1]
+ endif
+
+endin
+
+
+</CsInstruments>
+<CsScore>
+
+i "execscalar" 0 1
+i "execscalarstr" 2 1
+i "execarray" 4 1
+i "execarraystr" 6 1
+i "execscalar_k" 7 5
+i "execarray_k" 12 5
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/6-mysql-randomnotes.csd b/examples/6-mysql-randomnotes.csd
new file mode 100644
index 0000000..036b63a
--- /dev/null
+++ b/examples/6-mysql-randomnotes.csd
@@ -0,0 +1,99 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 3
+
+ Insert some frequencies and durations to a MySQL database
+ then query/play random pairs
+
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+seed 0
+
+
+; connect: type, hostname or IP, database name, username, password
+gidb dbconnect "mysql", "localhost", "databasename", "username", "password"
+
+
+; initialise the example
+instr start_example
+
+ ; create tables if not existing/truncate if existing and fill with frequency and duration data
+ dbexec gidb, "CREATE TABLE IF NOT EXISTS frequencies (freq FLOAT)"
+ dbexec gidb, "TRUNCATE TABLE frequencies"
+ dbexec gidb, "CREATE TABLE IF NOT EXISTS durations (dur FLOAT)"
+ dbexec gidb, "TRUNCATE TABLE durations"
+ dbexec gidb, "INSERT INTO frequencies (freq) VALUES (277.2), (349.272), (415.24559), (523.35359), (391.96079)"
+ dbexec gidb, "INSERT INTO frequencies (freq) SELECT freq*2 FROM frequencies"
+ dbexec gidb, "INSERT INTO durations (dur) VALUES (0.1), (0.2), (0.4), (0.8), (1), (1.2)"
+
+ ; run the sequencer instrument for 30 seconds
+ event_i "i", "sequence", 0, 30
+endin
+
+
+; random sequencer instrument
+instr sequence
+
+ ; query to return random frequency/duration pair
+ Sql = {{
+ SELECT f.freq, d.dur
+ FROM frequencies f
+ JOIN (SELECT dur FROM durations ORDER BY RAND() LIMIT 1) d
+ ORDER BY RAND()
+ LIMIT 1
+ }}
+
+ ; array needs to be initialised or schedkwhen complains
+ kevent[][] init 1, 2
+
+ ; query twice per second
+ ktrig metro 3
+
+ ; query on metro returning the frequency/duration pair
+ kdone, kevent[][] dbarray_k gidb, Sql, ktrig
+
+ ; schedule the note
+ schedkwhen kdone, 0, 0, "osc", 0, kevent[0][1], kevent[0][0]
+
+endin
+
+
+; play a note
+instr osc
+
+ ; pick a random waveform
+ ifn = int(random(1, 4))
+
+ ; set frequency and envelope
+ ifreq = p4
+ kamp line 0.5, p3, 0
+
+ ; play it
+ a1 oscil kamp, ifreq, ifn
+ outs a1, a1
+endin
+
+
+
+
+</CsInstruments>
+<CsScore>
+f1 0 16384 10 1
+f2 0 16384 10 1 0.5 0.3 0.25 0.2 0.167 0.14 0.125 .11
+f3 0 16384 10 1 0 0.3 0 0.2 0 0.14 0 .111
+f4 0 16384 10 1 1 1 1 0.7 0.5 0.3 0.1
+
+; begin example
+i "start_example" 0 1
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/7-violsqlite.csd b/examples/7-violsqlite.csd
new file mode 100644
index 0000000..cabc753
--- /dev/null
+++ b/examples/7-violsqlite.csd
@@ -0,0 +1,172 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 7
+
+ A rudimentary pitch tracking concatenative resynthesizer as such
+
+ This creates a sqlite database in memory, and then uses the opcode getpitches to scan through a
+ sound file in non-realtime, storing detected pitches and the relevant offset time of the pitch in
+ the database. The example file is a descending violin glissando.
+
+ When done, the instrument "playmatches" is scheduled twice which plays an oscillator varying in pitch,
+ which is pitch tracked and the nearest frequency is found in the database, prompting the "segment"
+ instrument to be scheduled with the relevant offset.
+
+
+ 1. for 20s in which nearest matches are played only if the detected pitch has changed outside of a threshold
+ 2. as above but with matches played continuously
+
+ The result is that the violin segments picked should moreorless match what the oscillator is doing.
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+
+
+; create an in-memory sqlite database and create a table
+gidb dbconnect "sqlite", ":memory:"
+dbexec gidb, "CREATE TABLE pitches (time REAL, cps REAL)"
+
+; file of ascending piano pitches
+gSfile = "sounds/violin.wav"
+gifn ftgen 0, 0, 0, 1, gSfile, 0, 0, 0
+
+; detect pitches and insert time/cps to database given a filename, in non-realtime
+opcode getpitches, 0, S
+ Sfile xin
+ ktimek timeinstk
+ ktime timeinsts
+ klast init -1
+ kcount init 0
+
+ ; run in the first single k-rate cycle
+ if (ktimek == 0) then
+
+ ; get file length in k-cycles
+ ilen filelen Sfile
+ kcycles = ilen * kr
+loop:
+ ; read file and track pitch
+ ain diskin2 Sfile, 1
+ ;ain butterbp ain, 500, 250
+ koct, kamp pitch ain, 0.01, 6, 12, 6, 12, 60
+
+ ; only take action if pitch has changed
+ kchanged changed2 koct
+ if (kchanged == 1) then
+
+ ; only store if cps is reasonably different from the last value
+ kcps = cpsoct(koct)
+
+ if (1==1) then
+
+ ; insert to database: the dbexec_kb opcode is k-rate but blocking/synchronous.
+ ; simpler to use for the non-realtime operation as regular _k opcodes are threaded/asynchronous
+ ktime = kcount / kr
+ Squery sprintfk "INSERT INTO pitches (time, cps) VALUES (%f, %f)", ktime, kcps
+ dbexec_kb gidb, Squery
+ klast = kcps
+ endif
+ endif
+ loop_lt kcount, 1, kcycles, loop
+
+ endif
+endop
+
+
+
+; begin the example: find pitches and then schedule the next step
+instr start_example
+ getpitches gSfile
+ schedkwhen 1, 0, 0, "playmatches", 0, 20, 0
+ schedkwhen 1, 0, 0, "playmatches", 20, 20, 1
+ turnoff
+
+endin
+
+
+
+; pitch follow a descending oscillator and attempt to find a similar cps in the database, then schedule segment accordingly
+instr playmatches
+ kdone init 0 ; for when the select query is done
+ klast init 0 ; last pitch played, in order to avoid repeats
+
+
+ ; oscillator
+ k1 linseg 400, p3, 200
+ ktime linseg 0.001, p3, 2
+ k2 oscil k1, ktime
+ ain oscil 1, abs(k2)+550, 1
+
+ ; track it
+ koct, kamp pitch ain, 0.01, 5, 10, 6, 12
+
+ ; only take action when the tracked pitch has changed
+ kchanged changed2 koct
+ if (kchanged == 1) then
+
+ ; (very roughly) get a near frequency match from the database
+ kcps = cpsoct(koct)
+
+ ; fairly nasty looking query for obtaining the nearest value
+ SquerySource = {{
+ SELECT time FROM (
+ SELECT time, cps FROM (
+ SELECT time, cps FROM pitches WHERE cps >= %f ORDER BY cps ASC LIMIT 1
+ )
+ UNION SELECT time, cps FROM (
+ SELECT time, cps FROM pitches WHERE cps < %f ORDER BY cps DESC LIMIT 1
+ )
+ ) x ORDER BY ABS(cps - %f) ASC LIMIT 1
+ }}
+
+ Squery sprintfk SquerySource, kcps, kcps, kcps
+ kdone, kpos dbscalar_k gidb, Squery, kchanged
+
+ ;schedule the notes
+ if (p4 == 1) then
+ schedkwhen kdone, 0, 0, "segment", 0, 0.2, kpos
+ else
+ if (kpos < klast*0.8 || kpos > klast*1.2) then
+ schedkwhen kdone, 0, 0, "segment", 0, 0.2, kpos
+ klast = kpos
+ endif
+ endif
+ endif
+
+
+ ; uncomment to hear the oscillator as well as pitch matched output
+ ;outs ain*0.01, ain*0.01
+endin
+
+
+
+; play part of the sound file given a skip time with a basic envelope
+instr segment
+ il = ftlen(gifn)
+ isec = il/sr
+ ist = sr*p4
+ icps = 1/isec
+ aphs phasor icps
+ andx = aphs * il
+ aout tablei andx+ist, gifn
+ kamp linseg 0, p3*0.3, 1, p3*0.4, 1, p3*0.3, 0
+ outs aout*0.1*kamp, aout*0.1*kamp
+endin
+
+
+</CsInstruments>
+<CsScore>
+f1 0 16384 10 1 0 0.3 0 0.2 0 0.14 0 .111 ; square wave
+
+i"start_example" 0 1
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file
diff --git a/examples/sounds/violin.wav b/examples/sounds/violin.wav
new file mode 100644
index 0000000..c490e1c
--- /dev/null
+++ b/examples/sounds/violin.wav
Binary files differ
diff --git a/examples/toCheck/7-sqlite-pitchmatcher.csd b/examples/toCheck/7-sqlite-pitchmatcher.csd
new file mode 100644
index 0000000..1d45234
--- /dev/null
+++ b/examples/toCheck/7-sqlite-pitchmatcher.csd
@@ -0,0 +1,140 @@
+<CsoundSynthesizer>
+<CsOptions>
+-odac
+</CsOptions>
+<CsInstruments>
+/*
+ EXAMPLE 9
+
+ A rudimentary pitch tracking concatenative resynthesizer
+
+ This creates a sqlite database in memory, and then uses the opcode getpitches to scan through a
+ sound file in non-realtime, storing detected pitches and the relevant offset time of the pitch in
+ the database. The example file is a series of ascending piano notes.
+
+ When done, the instrument "playmatches" is scheduled. This plays a descending oscillator
+ which is pitch tracked and then a similar pitch is found from the database, prompting the "segment"
+ instrument to be scheduled with the relevant offset.
+ The result is that the piano notes/sound file segments picked should moreorless match what the
+ oscillator is doing.
+
+*/
+
+sr = 44100
+kr = 4410
+nchnls = 2
+0dbfs = 1
+
+
+; create an in-memory sqlite database and create a table
+gidb dbconnect "sqlite", ":memory:"
+dbexec gidb, "CREATE TABLE pitches (time REAL, cps REAL)"
+
+; file of ascending piano pitches
+gSfile = "sounds/piano.wav"
+
+
+; detect pitches and insert time/cps to database given a filename, in non-realtime
+opcode getpitches, 0, S
+ Sfile xin
+ ktimek timeinstk
+ ktime timeinsts
+ klast init -1
+ kcount init 0
+
+ ; run in the first single k-rate cycle
+ if (ktimek == 0) then
+
+ ; get file length in k-cycles
+ ilen filelen Sfile
+ kcycles = ilen * kr
+loop:
+ ; read file and track pitch
+ ain diskin2 Sfile, 1
+ koct, kamp pitch ain, 0.01, 7, 11, 6, 12, 10, 8
+
+ ; only take action if pitch has changed
+ kchanged changed2 koct
+ if (kchanged == 1) then
+
+ ; only store if cps is reasonably different from the last value
+ kcps = cpsoct(koct)
+ if (kcps > klast*1.1 || kcps < klast*0.9) then
+
+ ; insert to database: the dbexec_kb opcode is k-rate but blocking/synchronous.
+ ; simpler to use for the non-realtime operation as regular _k opcodes are threaded/asynchronous
+ ktime = kcount / kr
+ Squery sprintfk "INSERT INTO pitches (time, cps) VALUES (%f, %f)", ktime, kcps
+ dbexec_kb gidb, Squery
+ klast = kcps
+ endif
+ endif
+ loop_lt kcount, 1, kcycles, loop
+
+ endif
+endop
+
+
+
+; begin the example: find pitches and then schedule the next step
+instr start_example
+ getpitches gSfile
+ schedkwhen 1, 0, 0, "playmatches", 0, 20
+ turnoff
+
+endin
+
+
+
+; pitch follow a descending oscillator and attempt to find a similar cps in the database, then schedule segment accordingly
+instr playmatches
+ kdone init 0 ; for when the select query is done
+ klast init 0 ; last pitch played, in order to avoid repeats
+
+ ; descending oscillator
+ k1 linseg 2000, p3, 200
+ ain oscil 1, k1, 1
+
+ ; track it
+ koct, kamp pitch ain, 0.01, 7, 11, 6, 12, 10, 8
+
+ ; only take action when the tracked pitch has changed
+ kchanged changed2 koct
+ if (kchanged == 1) then
+
+ ; (very roughly) get a near frequency match from the database
+ kcps = cpsoct(koct)
+ Squery sprintfk "SELECT time FROM pitches WHERE cps >= %f LIMIT 1", kcps
+ kdone, kpos dbscalar_k gidb, Squery, kchanged
+
+ ; don't repeat notes (try the schedkwhen outside of the if block for continuous play)
+ if (kpos != klast) then
+ schedkwhen kdone, 0, 0, "segment", 0, 0.2, kpos
+ klast = kpos
+ endif
+ endif
+
+ ; uncomment to hear the oscillator as well as pitch matched output
+ ;outs ain*0.01, ain*0.01
+endin
+
+
+
+; play part of the sound file given a skip time with a basic fade in/out
+instr segment
+ iskip = p4
+ kamp linseg 0, p3*0.1, 1, p3*0.8, 1, p3*0.1, 0
+ a1 diskin2 gSfile, 1, iskip
+ aout = a1*kamp * 0.1
+ outs aout, aout
+endin
+
+
+</CsInstruments>
+<CsScore>
+f1 0 16384 10 1 0 0.3 0 0.2 0 0.14 0 .111 ; square wave
+
+i"start_example" 0 1
+
+</CsScore>
+</CsoundSynthesizer> \ No newline at end of file