with CSound

This commit is contained in:
severak 2020-11-09 00:29:13 +01:00
parent f4c07713d5
commit 3bacd0c183
5 changed files with 224 additions and 11 deletions

View File

@ -32,3 +32,7 @@ see https://pinout.xyz/#
DT and CLK on rotary encoded can be switched without problems.
## credits
- https://medium.com/@ryanstewartalex/raspberry-pi-gpio-input-events-c9ba449ac5d5
- https://blog.amnuts.com/2017/01/11/rotary-volume-control-for-the-raspberry-pi/

77
ctcsoundSession.py Normal file
View File

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# ctcsoundSession.py:
#
# Copyright (C) 2016 Francois Pinot
#
# This code 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 of the License, or (at your option) any later version.
#
# This code 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this code; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
#
import os
import ctypes
import ctcsound
class CsoundSession(ctcsound.Csound):
"""A class for running a csound session"""
def __init__(self, csdFileName=None):
"""Start a csound session, eventually loading a csd file"""
ctcsound.Csound.__init__(self)
self.pt = None
if csdFileName and os.path.exists(csdFileName):
self.csd = csdFileName
self.startThread()
else:
self.csd = None
def startThread(self):
if self.compile_("csoundSession", self.csd) == 0:
self.pt = ctcsound.CsoundPerformanceThread(self.cs)
self.pt.play()
def resetSession(self, csdFileName=None):
"""Reset the current session, eventually loading a new csd file"""
if csdFileName and os.path.exists(csdFileName):
self.csd = csdFileName
if self.csd:
self.stopPerformance()
self.startThread()
def stopPerformance(self):
"""Stop the current score performance if any"""
if self.pt:
if self.pt.status() == 0:
self.pt.stop()
self.pt.join()
self.pt = None
self.cleanup()
def csdFileName(self):
"""Return the loaded csd filename or None"""
return self.csd
def note(self, pfields, absp2mode=0):
"""Send a score note to a csound instrument"""
return self.pt.scoreEvent(absp2mode, 'i', pfields)
def scoreEvent(self, eventType, pfields, absp2mode=False):
"""Send a score event to csound"""
self.pt.scoreEvent(absp2mode, eventType, pfields)
def flushMessages(self):
"""Wait until all pending messages are actually received by the performance thread"""
if self.pt:
self.pt.flushMessageQueue()

View File

@ -1,35 +1,101 @@
# Guinea synth
import sys
import time
from ctcsoundSession import CsoundSession
# todo - PIN numbers
def clip(value, lower, upper):
return lower if value < lower else upper if value > upper else value
class odpalovac:
value = 440
prev = None
csd = None
def __init__(self, prev, csd):
self.prev = prev
self.csd = csd
def show(self):
echo("Play note:")
echo("{} Hz".format(self.value), 1)
def up(self):
self.value = clip(self.value +1, 20, 22000)
self.show()
def down(self):
self.value = clip(self.value -1, 20, 22000)
self.show()
def push(self):
self.csd.note([1,0,0.5,self.value,0.5])
self.prev.show()
rotary(self.prev)
class param_cycle:
params = []
current = 0
def add(self, param):
self.params.append(param)
def up(self):
self.current = (self.current + 1) % len(self.params)
self.show()
def down(self):
self.current = (self.current - 1) % len(self.params)
self.show()
def show(self):
self.params[self.current].show()
def push(self):
self.params[self.current].show()
rotary(self.params[self.current])
class hladina:
value = 0
prev = None
name = ""
def __init__(self, prev, name):
self.prev = prev
self.name = name
def show(self):
echo(self.name)
echo("{}".format(self.value), 1)
def up(self):
self.value += 1
echo("vol {}%".format(self.value))
self.show()
def down(self):
self.value -= 1
echo("vol {}%".format(self.value))
self.show()
def push(self):
self.value = 0
echo("vol {}%".format(self.value))
self.prev.show()
rotary(self.prev)
# main
_rotary = None
print("Guinea synth")
if "--test" in sys.argv:
print("(using Tkinter emulation)")
if "--tkinter" in sys.argv:
print("(using Tkinter emulation instead of hardware)")
import tkinter as tk
window = tk.Tk()
window.geometry("200x150")
rows = [None, None]
rows[0] = tk.StringVar()
tk.Label(text="", textvariable=rows[0]).pack()
@ -59,9 +125,30 @@ if "--test" in sys.argv:
else:
print("(using hardware controls)")
# TODO - zde bude ovládání rotačního enkodéru a diplaye
######
try:
cls()
echo("Guinea synth")
echo("READY", 1)
rotary(hladina())
print("OK")
csd = CsoundSession("minimal.csd")
csd.setControlChannel("filter", 2000)
print(csd)
print(csd.audioDevList(True))
print(csd.csdFileName())
menu = param_cycle()
menu.add(odpalovac(menu, csd))
menu.add(hladina(menu, "volume"))
menu.add(hladina(menu, "tone"))
cls()
echo("Guinea synth")
echo("READY", 1)
rotary(menu)
print("OK")
finally:
csd.stopPerformance()
del csd

34
minimal.csd Normal file
View File

@ -0,0 +1,34 @@
<CsoundSynthesizer>
<CsOptions>
; silent, default DAC, PortMidi and all inputs, cps to p4, velocity to p5
-d -odac -+rtmidi=PortMidi -Ma --midi-key-cps=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
; Initialize the global variables.
ksmps = 32
nchnls = 2
0dbfs = 1
;instrument will be triggered by keyboard widget
instr 1
kfilter chnget "filter"
; TODO - volume
kamp = 0.5
kEnv madsr .1, .2, .6, .4
; kamp, kcps
aOut vco2 kamp, p4, 12
aOut moogladder2 aOut, kfilter, 0
outs aOut*kEnv, aOut*kEnv
endin
</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
i1 0 0.5 440
;i1 1 0.5 880
</CsScore>
</CsoundSynthesizer>

11
testCsound.py Normal file
View File

@ -0,0 +1,11 @@
import time
from ctcsoundSession import *
cs = CsoundSession()
cs.setControlChannel("filter", 2000)
cs.resetSession("minimal.csd")
print("play:")
time.sleep(60)
cs.stopPerformance()
del cs
print("OK")