with CSound
This commit is contained in:
parent
f4c07713d5
commit
3bacd0c183
|
@ -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/
|
|
@ -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()
|
109
guinea-synth.py
109
guinea-synth.py
|
@ -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
|
|
@ -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>
|
|
@ -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")
|
Loading…
Reference in New Issue