raspberry pi zero based drum machine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

main.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. import sys
  2. sys.path.insert(0, './lib')
  3. from pygame import mixer
  4. import time
  5. import digitalio
  6. import board
  7. import adafruit_matrixkeypad
  8. import pygame
  9. from PIL import Image, ImageDraw, ImageFont
  10. import adafruit_rgb_display.st7789 as st7789
  11. import digitalio
  12. import board
  13. from adafruit_rgb_display.rgb import color565
  14. import adafruit_rgb_display.st7789 as st7789
  15. import FSM
  16. from itertools import cycle
  17. import observer
  18. from scikits.samplerate import resample
  19. from configobj import ConfigObj
  20. import ast
  21. #from configobj import ConfigObj
  22. import RPi.GPIO as GPIO
  23. from time import sleep
  24. GPIO.setmode(GPIO.BCM)
  25. # set up GPIO output channel
  26. GPIO.setup(47, GPIO.OUT)
  27. cols = [digitalio.DigitalInOut(x) for x in (board.D21, board.D20, board.D16, board.D12)]
  28. rows = [digitalio.DigitalInOut(x) for x in (board.D26, board.D13, board.D6, board.D5)]
  29. # keys = ((3, 2, 1, 0),
  30. # (7, 6, 5, 4),
  31. # (11, 10, 9, 8),
  32. # (15, 14, 13, 12))
  33. keys = ((15, 14, 13, 12),
  34. (11, 10, 9, 8),
  35. (7, 6, 5, 4),
  36. (3, 2, 1, 0))
  37. keypad = adafruit_matrixkeypad.Matrix_Keypad(rows, cols, keys)
  38. # while True:
  39. # keys = keypad.pressed_keys
  40. # if keys:
  41. # print("Pressed: ", keys)
  42. # time.sleep(0.1)
  43. pygame.init()
  44. mixer.init()
  45. done = False
  46. clock = pygame.time.Clock()
  47. TIMER = pygame.USEREVENT + 1
  48. #pygame.time.set_timer(pygame.USEREVENT + 1, 444)
  49. #pygame.time.set_timer(TIMER, 161)
  50. playhead = 0
  51. timer = pygame.time.get_ticks
  52. start = now = timer()
  53. cs_pin = digitalio.DigitalInOut(board.CE0)
  54. dc_pin = digitalio.DigitalInOut(board.D25)
  55. reset_pin = None
  56. BAUDRATE = 64000000 # The pi can be very fast!
  57. # display = st7789.ST7789(
  58. # board.SPI(),
  59. # cs=cs_pin,
  60. # dc=dc_pin,
  61. # rst=reset_pin,
  62. # baudrate=BAUDRATE,
  63. # width=135,
  64. # height=240,
  65. # x_offset=53,
  66. # y_offset=40,
  67. # )
  68. backlight = digitalio.DigitalInOut(board.D22)
  69. backlight.switch_to_output()
  70. backlight.value = True
  71. buttonA = digitalio.DigitalInOut(board.D23)
  72. buttonB = digitalio.DigitalInOut(board.D24)
  73. buttonA.switch_to_input()
  74. buttonB.switch_to_input()
  75. spi = board.SPI()
  76. # Create blank image for drawing.
  77. # Make sure to create image with mode 'RGB' for full color.
  78. # Get drawing object to draw on image.
  79. # Draw a black filled box to clear the image.
  80. #draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))
  81. #disp.image(image, rotation)
  82. # Draw some shapes.
  83. # First define some constants to allow easy resizing of shapes.
  84. # Move left to right keeping track of the current x position for drawing shapes.
  85. x = 0
  86. # Turn on the backlight
  87. backlight = digitalio.DigitalInOut(board.D22)
  88. backlight.switch_to_output()
  89. backlight.value = True
  90. class Prog:
  91. def __init__(self):
  92. self.FSM = FSM.ProgFSM(self)
  93. self.font = ImageFont.truetype("/home/pi/examples/HLM.ttf", 64)
  94. #self.h1 = ImageFont.truetype("/home/pi/examples/HLM.ttf", 26)
  95. self.h1 = ImageFont.truetype("/home/pi/Pixellari.ttf", 30)
  96. self.h2 = ImageFont.truetype("/home/pi/Pixellari.ttf", 20)
  97. self.h3 = ImageFont.truetype("/home/pi/Pixellari.ttf", 54)
  98. self.disp = st7789.ST7789(
  99. spi,
  100. cs=cs_pin,
  101. dc=dc_pin,
  102. rst=reset_pin,
  103. baudrate=BAUDRATE,
  104. width=135,
  105. height=240,
  106. x_offset=53,
  107. y_offset=40,
  108. )
  109. self.height = self.disp.width # we swap height/width to rotate it to landscape!
  110. self.width = self.disp.height
  111. self.rotation = 270
  112. self.padding = -2
  113. self.top = self.padding
  114. self.bottom = self.height - self.padding
  115. self.image = Image.new("RGB", (self.width, self.height))
  116. self.draw = ImageDraw.Draw(self.image)
  117. self.playhead = 0
  118. self.playing = False
  119. #self.bpm = 90
  120. self.bpm_inc = 1
  121. self.note_bank = 0
  122. self.volume = 10
  123. self.note_vol = 16
  124. self.note_pitch = 0.0
  125. self.soundSlots = []
  126. self.keys = []
  127. self.keyState = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
  128. #self.song = [2, 3, 0, 1, 0, 1, 0, 1, 0, 1]
  129. self.song = [0]
  130. self.songCycle = cycle(self.song)
  131. self.curPattern = next(self.songCycle)
  132. self.songStart = self.curPattern
  133. self.eSound = 0
  134. self.ePattern = 0
  135. self.black = "#000000"
  136. self.bg_color = "#336699"
  137. self.color_a = "#FFFFFF"
  138. self.color_b = "#929230"
  139. self.color_c = "#FFFF00"
  140. self.dark_grey = "#404040"
  141. self.grey = "#808080"
  142. self.light_grey = "#D3D3D3"
  143. self.blue = "#336699"
  144. self.dark_blue = "#2A2AD5"
  145. self.pink = "#D52A80"
  146. self.red = "#D52A2A"
  147. self.olive = "#80D52A"
  148. self.green = "#2AD52A"
  149. self.pub = observer.Publisher(['beat', 'the joint'])
  150. self.song_file_name = "default.sng"
  151. self.mconf = ConfigObj("config.txt")
  152. self.sconf = ConfigObj("/home/pi/zpc_ct/user/songs/" + self.mconf['default_song'])
  153. self.theme = ConfigObj("/home/pi/zpc_ct/themes/" + self.mconf['theme'])
  154. self.light_grey = self.theme['light_grey']
  155. self.apply_theme()
  156. #self.config['title'] = "default"
  157. #self.config['bpm'] = self.bpm
  158. #self.config['volume'] = self.volume
  159. #self.config.write()
  160. #self.save_song()
  161. class SoundSlot:
  162. def __init__(self, file, obj_id, o):
  163. self.file = file
  164. self.id = obj_id
  165. self.o = o
  166. self.mixerSound = pygame.mixer.Sound(self.file)
  167. self.og_sound = self.mixerSound
  168. self.pattern = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]
  169. self.notes = self.init_notes()
  170. self.pitch = 0.0
  171. self.volume = 16
  172. self.start = 0
  173. self.end = 0
  174. def play(self, vol):
  175. # snd_array = pygame.sndarray.array(self.mixerSound)
  176. # snd_resample = resample(snd_array, 2.5, "sinc_fastest").astype(snd_array.dtype)
  177. # snd_out = pygame.sndarray.make_sound(snd_resample)
  178. # snd_out.play()
  179. if vol != 0:
  180. vol = (vol / 16) * (self.volume / 16) * (self.o.volume / 16)
  181. self.mixerSound.set_volume(vol)
  182. pygame.mixer.Sound.play(self.mixerSound)
  183. def init_notes(self):
  184. #print('initing notes')
  185. outp = []
  186. _id = 0
  187. while _id < 64:
  188. outp2 = []
  189. _id2 = 0
  190. while _id2 < 16:
  191. outp2.append([0,16])
  192. _id2 += 1
  193. outp.append(outp2)
  194. _id += 1
  195. # for n in outp:
  196. # print('sound ', self.id, ' ', n)
  197. #print(outp)
  198. return outp
  199. def Execute(self):
  200. #print('doing the thing')
  201. #self.check_buttons()
  202. self.keys = keypad.pressed_keys
  203. #self.key_flip()
  204. self.update_keys()
  205. self.FSM.Execute()
  206. #self.disp.image(self.image, self.rotation)
  207. def update_keys(self):
  208. _id = 0
  209. for k in self.keyState:
  210. if k == 0:
  211. if _id in self.keys:
  212. self.keyState[_id] = 1
  213. elif k == 1:
  214. if _id in self.keys:
  215. self.keyState[_id] = 2
  216. else:
  217. self.keyState[_id] = 3
  218. elif k == 2:
  219. if _id in self.keys:
  220. self.keyState[_id] = 2
  221. else:
  222. self.keyState[_id] = 3
  223. else:
  224. self.keyState[_id] = 0
  225. _id += 1
  226. if buttonA.value == 0:
  227. #print('a on `', self.keyState[16])
  228. if self.keyState[16] == 0:
  229. self.keyState[16] = 1
  230. elif self.keyState[16] == 1:
  231. self.keyState[16] = 2
  232. else:
  233. self.keyState[16] = 2
  234. else:
  235. if self.keyState[16] == 3:
  236. self.keyState[16] = 4
  237. elif self.keyState[16] == 2:
  238. self.keyState[16] = 3
  239. elif self.keyState[16] == 4:
  240. self.keyState[16] = 0
  241. if buttonB.value == 0:
  242. #print('a on `', self.keyState[16])
  243. if self.keyState[17] == 0:
  244. self.keyState[17] = 1
  245. elif self.keyState[17] == 1:
  246. self.keyState[17] = 2
  247. else:
  248. self.keyState[17] = 2
  249. else:
  250. if self.keyState[17] == 3:
  251. self.keyState[17] = 4
  252. elif self.keyState[17] == 2:
  253. self.keyState[17] = 3
  254. elif self.keyState[17] == 4:
  255. self.keyState[17] = 0
  256. # if buttonB.value == 0:
  257. # #print('b on')
  258. # if self.keyState[17] == 0 or self.keyState[17] == 1:
  259. # self.keyState[17] += 1
  260. # else:
  261. # if self.keyState[17] == 2:
  262. # self.keyState[17] += 1
  263. # else:
  264. # self.keyState[17] = 0
  265. def update_bpm(self):
  266. bpm = (60000 / self.sconf['bpm']) / 4
  267. pygame.time.set_timer(TIMER, int(bpm))
  268. def start_playback(self):
  269. self.playing = True
  270. self.playhead = -1
  271. self.playhead = 0
  272. #self.songCycle = cycle(self.song)
  273. #self.curPattern = next(self.songCycle)
  274. #self.songStart = self.curPattern
  275. #self.curPattern = self.song[0]
  276. #self.curPattern = self.songStart
  277. self.songCycle = cycle(self.song)
  278. self.curPattern = next(self.songCycle)
  279. self.songStart = self.curPattern
  280. bpm = (60000 / self.sconf.as_int('bpm')) / 4
  281. pygame.time.set_timer(TIMER, int(bpm))
  282. def stop_playback(self):
  283. self.playing = False
  284. self.playhead = -1
  285. self.playhead = 0
  286. self.curPattern = self.song[0]
  287. #self.curPattern = self.songStart
  288. pygame.time.set_timer(TIMER, 0)
  289. def center_text(self, text, font, width, y, color):
  290. w,h = font.getsize(text)
  291. self.draw.text(((width-w)/2,(y-h)/2), text, font=font, fill=color)
  292. def center_block(self, message, font, bounding_box, color):
  293. x1, y1, x2, y2 = bounding_box # For easy reading
  294. w, h = self.draw.textsize(message, font=font)
  295. x = (x2 - x1 - w)/2 + x1
  296. y = (y2 - y1 - h)/2 + y1
  297. self.draw.text((x, y), message, align='center', font=font, fill=color)
  298. def apply_theme(self):
  299. self.light_grey = self.theme["light_grey"]
  300. self.blue = self.theme["blue"]
  301. self.pink = self.theme["pink"]
  302. self.olive = self.theme["olive"]
  303. self.black = self.theme["black"]
  304. self.dark_blue = self.theme["dark_blue"]
  305. self.green = self.theme["green"]
  306. self.red = self.theme["red"]
  307. def save_song(self):
  308. base_dir = "/home/pi/zpc_ct/user/songs/"
  309. #self.song_file_name
  310. #file1 = open(base_dir + self.song_file_name,"w")#write mode
  311. #file1.write("Tomorrow \n")
  312. #file1.close()
  313. self.sconf = ConfigObj(base_dir + self.song_file_name)
  314. self.sconf['title'] = "default"
  315. #self.config['bpm'] = self.bpm
  316. self.sconf['volume'] = self.volume
  317. sounds = []
  318. notes = []
  319. vols = []
  320. pitches = []
  321. for x in self.soundSlots:
  322. sounds.append(x.file)
  323. notes.append(x.notes)
  324. vols.append(x.volume)
  325. pitches.append(x.pitch)
  326. self.sconf['sounds'] = sounds
  327. self.sconf['notes'] = notes
  328. self.sconf['song'] = self.song
  329. #self.config['volumes'] = ['this', 'that', 'the other']
  330. self.sconf.write()
  331. def load_song(self):
  332. base_dir = "/home/pi/zpc_ct/user/songs/"
  333. self.sconf = ConfigObj(base_dir + 'default.sng')
  334. one = self.sconf['song']
  335. #two = ast.literal_eval(self.sconf['song'])
  336. three = self.sconf.as_list('song')
  337. #four = ast.literal_eval(self.sconf.as_list('song'))
  338. song = []
  339. for i in self.sconf['song']:
  340. song.append(int(i))
  341. #lst = ast.literal_eval(self.sconf['song'][0])
  342. self.song = song
  343. print('this is the song')
  344. #print(lst)
  345. print(song)
  346. #print(two)
  347. #print(three)
  348. #print(four)
  349. #print(five)
  350. self.songCycle = cycle(self.song)
  351. self.curPattern = next(self.songCycle)
  352. self.songStart = self.curPattern
  353. #self.config = ConfigObj(base_dir + self.song_file_name)
  354. #print('these sounds should get loaded ', self.config['sounds'])
  355. p = Prog()
  356. #while True:
  357. while not done:
  358. p.Execute()
  359. if pygame.event.get(pygame.USEREVENT + 1):
  360. if p.playhead == 0:
  361. print('pattern ', p.curPattern)
  362. p.playhead += 1
  363. if p.playhead == 16:
  364. p.playhead = 0
  365. #self.draw.text((0, 0), str(self.playhead), font=font, fill="#FFFFFF")
  366. #self.disp.image(self.image, self.rotation)
  367. p.curPattern = next(p.songCycle)
  368. #print('pattern ', p.curPattern)
  369. if p.playhead % 8 == 0:
  370. GPIO.setup(47, GPIO.OUT)
  371. GPIO.output(47, GPIO.LOW)
  372. #print('led on')
  373. else:
  374. GPIO.setup(47, GPIO.OUT)
  375. GPIO.output(47, GPIO.HIGH)
  376. #print('led off')
  377. p.pub.dispatch('beat', [p.curPattern, p.playhead])
  378. #clock.tick(240)
  379. clock.tick_busy_loop()
  380. #print(clock.get_fps())
  381. pygame.quit()
  382. # 1 main
  383. # 2 select pattern
  384. # 3 note edit
  385. # 6 song edit
  386. # 7 program load
  387. # 8 song load
  388. # 10 utility
  389. # 11 bpm+
  390. # 12 bpm-
  391. # 13 play
  392. # 14 stop
  393. # 15 vol+
  394. # 16 vol-