Parcourir la source

better concurrecny

Johann Woelper il y a 4 ans
Parent
commit
ef6cd2efad

+ 8 - 0
patterns/Rostock One.pat

@@ -0,0 +1,8 @@
+{
+  "name": "Rostock One",
+  "repeat": 8,
+  "resolution": 0,
+  "xsize": 8,
+  "ysize": 3,
+  "sounds": {}
+}

+ 75 - 75
patterns/berlin.pat

@@ -1,217 +1,217 @@
 {
   "name": "berlin",
   "repeat": 1,
-  "bpm": 120,
+  "resolution": 8,
   "xsize": 16,
   "ysize": 6,
   "sounds": {
-    "12,1": {
-      "name": "kick_low.wav",
-      "location": "media/cc0/kick_low.wav",
+    "1,3": {
+      "name": "hihiat_closed.wav",
+      "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "11,3": {
-      "name": "hihiat_closed.wav",
-      "location": "media/cc0/hihiat_closed.wav",
+    "8,1": {
+      "name": "kick_low.wav",
+      "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "2,2": {
-      "name": "snare_sharp.wav",
-      "location": "media/cc0/snare_sharp.wav",
+    "13,3": {
+      "name": "hihiat_closed.wav",
+      "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "14,2": {
-      "name": "snare_sharp.wav",
-      "location": "media/cc0/snare_sharp.wav",
+    "11,3": {
+      "name": "hihiat_closed.wav",
+      "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "15,3": {
-      "name": "hihiat_closed.wav",
-      "location": "media/cc0/hihiat_closed.wav",
+    "0,4": {
+      "name": "bass_303.wav",
+      "location": "media/cc0/bass/bass_303.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "speed": 1.0,
+      "trim": 0,
+      "speed": 0.960125,
       "reverse": false
     },
-    "0,1": {
+    "10,1": {
       "name": "kick_low.wav",
       "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "14,1": {
-      "name": "kick_low.wav",
-      "location": "media/cc0/kick_low.wav",
+    "6,2": {
+      "name": "snare_sharp.wav",
+      "location": "media/cc0/snare_sharp.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "8,1": {
+    "14,1": {
       "name": "kick_low.wav",
       "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "5,3": {
+    "7,3": {
       "name": "hihiat_closed.wav",
       "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "7,3": {
-      "name": "hihiat_closed.wav",
-      "location": "media/cc0/hihiat_closed.wav",
+    "2,1": {
+      "name": "kick_low.wav",
+      "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "3,3": {
+    "15,3": {
       "name": "hihiat_closed.wav",
       "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "6,2": {
-      "name": "snare_sharp.wav",
-      "location": "media/cc0/snare_sharp.wav",
+    "12,1": {
+      "name": "kick_low.wav",
+      "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "9,3": {
-      "name": "hihiat_closed.wav",
-      "location": "media/cc0/hihiat_closed.wav",
+    "6,1": {
+      "name": "kick_low.wav",
+      "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "1,3": {
+    "9,3": {
       "name": "hihiat_closed.wav",
       "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "10,1": {
-      "name": "kick_low.wav",
-      "location": "media/cc0/kick_low.wav",
+    "10,2": {
+      "name": "snare_sharp.wav",
+      "location": "media/cc0/snare_sharp.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "10,2": {
-      "name": "snare_sharp.wav",
-      "location": "media/cc0/snare_sharp.wav",
+    "5,3": {
+      "name": "hihiat_closed.wav",
+      "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "4,1": {
-      "name": "kick_low.wav",
-      "location": "media/cc0/kick_low.wav",
+    "3,3": {
+      "name": "hihiat_closed.wav",
+      "location": "media/cc0/hihiat_closed.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "13,3": {
-      "name": "hihiat_closed.wav",
-      "location": "media/cc0/hihiat_closed.wav",
+    "4,1": {
+      "name": "kick_low.wav",
+      "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "0,4": {
-      "name": "bass_303.wav",
-      "location": "media/cc0/bass/bass_303.wav",
+    "2,2": {
+      "name": "snare_sharp.wav",
+      "location": "media/cc0/snare_sharp.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "speed": 0.960125,
+      "trim": 0,
+      "speed": 1.0,
       "reverse": false
     },
-    "2,1": {
+    "0,1": {
       "name": "kick_low.wav",
       "location": "media/cc0/kick_low.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     },
-    "6,1": {
-      "name": "kick_low.wav",
-      "location": "media/cc0/kick_low.wav",
+    "14,2": {
+      "name": "snare_sharp.wav",
+      "location": "media/cc0/snare_sharp.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
+      "trim": 0,
       "speed": 1.0,
       "reverse": false
     }

+ 75 - 75
patterns/cold sweat.pat

@@ -1,159 +1,159 @@
 {
   "name": "cold sweat",
   "repeat": 1,
-  "bpm": 384,
+  "resolution": 8,
   "xsize": 16,
   "ysize": 3,
   "sounds": {
-    "7,1": {
+    "15,1": {
       "name": "snare_jungle.wav",
       "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
+    "4,2": {
+      "name": "ride_bell2.wav",
+      "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "10,2": {
+      "name": "ride_bell2.wav",
+      "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "7,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,2": {
+    "12,2": {
       "name": "ride_bell2.wav",
       "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "15,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
+    "6,2": {
+      "name": "ride_bell2.wav",
+      "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "0,2": {
+    "14,2": {
       "name": "ride_bell2.wav",
       "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,2": {
+    "8,2": {
       "name": "ride_bell2.wav",
       "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "2,2": {
-      "name": "ride_bell2.wav",
-      "location": "media\\cc0\\ride_bell.wav",
+    "10,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "0,0": {
+    "8,0": {
       "name": "kick_rough.wav",
       "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "6,2": {
+    "2,2": {
       "name": "ride_bell2.wav",
       "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,1": {
+    "12,1": {
       "name": "snare_jungle.wav",
       "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,2": {
-      "name": "ride_bell2.wav",
-      "location": "media\\cc0\\ride_bell.wav",
+    "4,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "14,2": {
+    "0,2": {
       "name": "ride_bell2.wav",
       "location": "media\\cc0\\ride_bell.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,2": {
-      "name": "ride_bell2.wav",
-      "location": "media\\cc0\\ride_bell.wav",
+    "0,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     }
   }
 }

+ 132 - 132
patterns/funky drummer.pat

@@ -1,189 +1,189 @@
 {
   "name": "funky drummer",
   "repeat": 1,
-  "bpm": 416,
+  "resolution": 8,
   "xsize": 16,
   "ysize": 3,
   "sounds": {
-    "7,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
+    "15,2": {
+      "name": "hihiat_closed.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "9,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
+    "2,0": {
+      "name": "kick_edm.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,2": {
+    "5,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,1": {
+    "9,1": {
       "name": "snare_jungle.wav",
       "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "6,0": {
-      "name": "kick_edm.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "15,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "11,2": {
-      "name": "hihiat_closed.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "4,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "7,2": {
+    "3,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,2": {
-      "name": "hihiat_closed.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "6,0": {
+      "name": "kick_edm.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,2": {
+    "12,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "5,2": {
+    "8,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,0": {
-      "name": "kick_edm.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "11,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "9,2": {
+    "6,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "14,2": {
-      "name": "hihiat_closed.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "13,0": {
+      "name": "kick_edm.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "15,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
+    "4,2": {
+      "name": "hihiat_closed.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "2,0": {
-      "name": "kick_edm.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "7,2": {
+      "name": "hihiat_closed.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "13,0": {
+    "0,0": {
       "name": "kick_edm.wav",
       "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "3,2": {
+    "11,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "6,2": {
+    "10,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "1,2": {
       "name": "hihiat_closed.wav",
@@ -191,79 +191,79 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,1": {
-      "name": "snare_jungle.wav",
-      "location": "media\\cc0\\snare_jungle.wav",
-      "volume": 1.0,
-      "roll": 0,
-      "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
-    },
-    "0,2": {
+    "2,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "2,2": {
-      "name": "hihiat_closed.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "10,0": {
+      "name": "kick_edm.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "15,2": {
+    "0,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,2": {
+    "9,2": {
       "name": "hihiat_closed.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "0,0": {
-      "name": "kick_edm.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "7,1": {
+      "name": "snare_jungle.wav",
+      "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "11,1": {
+    "12,1": {
       "name": "snare_jungle.wav",
       "location": "media\\cc0\\snare_jungle.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
+    },
+    "14,2": {
+      "name": "hihiat_closed.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
+      "volume": 1.0,
+      "roll": 0,
+      "rollrate": 0,
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     }
   }
 }

+ 71 - 71
patterns/impeach the president.pat

@@ -1,29 +1,29 @@
 {
   "name": "impeach the president",
   "repeat": 1,
-  "bpm": 416,
+  "resolution": 8,
   "xsize": 16,
   "ysize": 3,
   "sounds": {
-    "0,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "14,2": {
+      "name": "hihiat_real.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,1": {
-      "name": "snare_organic.wav",
-      "location": "media\\cc0\\snare_organic.wav",
+    "7,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "6,2": {
       "name": "hihiat_real.wav",
@@ -31,39 +31,39 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,2": {
+    "2,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "14,2": {
-      "name": "hihiat_real.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "12,1": {
+      "name": "snare_organic.wav",
+      "location": "media\\cc0\\snare_organic.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "4,1": {
+      "name": "snare_organic.wav",
+      "location": "media\\cc0\\snare_organic.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "14,0": {
       "name": "kick_rough.wav",
@@ -71,79 +71,79 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
-    },
-    "7,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
-      "volume": 1.0,
-      "roll": 0,
-      "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,2": {
+    "10,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "0,2": {
+    "12,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,1": {
-      "name": "snare_organic.wav",
-      "location": "media\\cc0\\snare_organic.wav",
+    "0,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "2,2": {
+    "8,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,2": {
+    "4,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,2": {
+    "8,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
+      "volume": 1.0,
+      "roll": 0,
+      "rollrate": 0,
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
+    },
+    "0,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     }
   }
 }

+ 74 - 74
patterns/when the levee breaks.pat

@@ -1,39 +1,39 @@
 {
   "name": "when the levee breaks",
   "repeat": 1,
-  "bpm": 396,
+  "resolution": 8,
   "xsize": 16,
   "ysize": 3,
   "sounds": {
-    "0,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "10,2": {
+      "name": "hihiat_real.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "8,2": {
-      "name": "hihiat_real.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "1,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "2,2": {
+    "6,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "11,0": {
       "name": "kick_rough.wav",
@@ -41,39 +41,39 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,2": {
-      "name": "hihiat_real.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "7,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "0,2": {
-      "name": "hihiat_real.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "10,0": {
+      "name": "kick_rough.wav",
+      "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "7,0": {
+    "0,0": {
       "name": "kick_rough.wav",
       "location": "media\\cc0\\kick_rough.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "4,1": {
       "name": "snare_deep.wav",
@@ -81,19 +81,19 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "1,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "14,2": {
+      "name": "hihiat_real.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
     "12,2": {
       "name": "hihiat_real.wav",
@@ -101,59 +101,59 @@
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "6,2": {
+    "0,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "4,2": {
-      "name": "hihiat_real.wav",
-      "location": "media\\cc0\\hihiat_real.wav",
+    "12,1": {
+      "name": "snare_deep.wav",
+      "location": "media\\cc0\\snare_deep.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "10,0": {
-      "name": "kick_rough.wav",
-      "location": "media\\cc0\\kick_rough.wav",
+    "8,2": {
+      "name": "hihiat_real.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "14,2": {
+    "2,2": {
       "name": "hihiat_real.wav",
       "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     },
-    "12,1": {
-      "name": "snare_deep.wav",
-      "location": "media\\cc0\\snare_deep.wav",
+    "4,2": {
+      "name": "hihiat_real.wav",
+      "location": "media\\cc0\\hihiat_real.wav",
       "volume": 1.0,
       "roll": 0,
       "rollrate": 0,
-      "trim": 0.0,
-      "active": false,
-      "speed": 1.0
+      "trim": 0,
+      "speed": 1.0,
+      "reverse": false
     }
   }
 }

+ 129 - 66
src/base.rs

@@ -1,19 +1,18 @@
 use std::path::{Path, PathBuf};
-// use std::io::BufReader;
 use std::thread;
 use std::time::Duration;
 use std::fs::File;
 use std::io::{Cursor, Read};
-use std::sync::Arc;
+use std::sync::{Arc, Mutex};
+use std::io::{BufWriter, BufReader};
+use std::collections::HashMap;
 use rodio::Decoder;
 use crate::rodio::Source;
-
-use std::io::BufWriter;
-use std::io::BufReader;
-use std::collections::HashMap;
 use serde::{Serializer};
 use crate::serde::ser::SerializeMap;
+use std::sync::MutexGuard;
 // pub fn collect
+use log::*;
 
 
 #[derive(Serialize, Deserialize, Clone, Default, Debug)]
@@ -28,7 +27,10 @@ pub struct Sound {
     pub roll: i32,
     pub rollrate: i32,
     pub trim: i32,
-      pub speed: f32,
+    #[serde(skip)]
+    // pub active: bool,
+    pub active: Arc<Mutex<bool>>,
+    pub speed: f32,
     #[serde(default)]
     pub reverse: bool
 }
@@ -113,6 +115,8 @@ impl Sound {
             _ => self.rollrate
         };
 
+        *self.active.lock().unwrap() = true;
+        // *self.active = true;
         if self.roll == 0 {
             match Decoder::new(self.cursor()) {
                 Ok(ok_decoder) => {
@@ -130,11 +134,17 @@ impl Sound {
                             .speed(self.speed)
                             .amplify(self.volume)
                             .convert_samples());
-                    }
 
+                        // match rodio::play_once(&device, ok_decoder) {
+                        //     Ok(s) => {},
+                        //     Err(_) => {}
+                        // }
+ 
+                    
+                        }
+                    thread::sleep(Duration::from_millis(delay));
 
 
-    
                 }
                 Err(e) => {
                     dbg!(e);
@@ -142,6 +152,7 @@ impl Sound {
             }
 
         } else {
+            // Roll the sound
             for _ in 0..self.roll+1 {
     
                 match Decoder::new(self.cursor()) {
@@ -150,7 +161,7 @@ impl Sound {
                         rodio::play_raw(&device, ok_decoder
                             .speed(self.speed)
                             .amplify(self.volume)
-                            .take_duration(Duration::from_millis(delay / rollrate as u64))
+                            // .take_duration(Duration::from_millis(delay / rollrate as u64))
                             .convert_samples());
         
                     }
@@ -159,10 +170,9 @@ impl Sound {
                     }
                 }
             thread::sleep(Duration::from_millis(delay / rollrate as u64 ));
-
-
             }
         }
+        *self.active.lock().unwrap() = false;
     }
 }
 
@@ -214,12 +224,14 @@ D: serde::de::Deserializer<'de>,
 pub struct Pattern {
     pub name: String,
     pub repeat: i32,
+    #[serde(default)]
+    pub resolution: i32,
     pub xsize: usize,
     pub ysize: usize,
     #[serde(serialize_with="ser_snds", deserialize_with="de_snds")]
     pub sounds: HashMap<(usize, usize), Sound>,
     #[serde(skip)]
-    pub progress: Option<(usize, usize)>
+    pub snds: Arc<Mutex<HashMap<(usize, usize), Sound>>>
 }
 
 /// Some basic defaults for a pattern.
@@ -228,48 +240,74 @@ impl Default for Pattern {
         Pattern {
             name: "Unnamed".to_string(),
             repeat: 0,
+            resolution: 8,
             xsize: 8,
             ysize: 1,
             sounds: HashMap::new(),
-            progress: None
+            snds: Arc::new(Mutex::new(HashMap::new()))
         }
     }
 }
 
 impl Pattern {
-    pub fn play(&self, device: &Arc<rodio::Device>, bpm: i32) {
 
-        let pat_clone = self.clone();
+    // pub fn play(&self, device: &Arc<rodio::Device>, bpm: i32) {
+
+    //     let pat_clone = Arc::new(self.clone());
+    //     // let pat_clone = self.clone();
+    //     let device = device.clone();
+    //     let delay = ((60.0 / bpm as f32)*1000.0) as u64;
+        
+    //     thread::spawn(move || {
+            
+    //         // loop for repeats
+    //         for _ in 0..pat_clone.repeat + 1 {
+    //             for x in 0..pat_clone.xsize {
+    //                 for y in 0..pat_clone.ysize {
+    //                     let device = device.clone();
+    //                     if let Some(s) = pat_clone.sounds.get(&(x, y)) {
+    //                         let s = s.clone();
+    //                         thread::spawn(move || {
+    //                             s.play(&device, bpm);
+    //                         });
+
+    //                     }
+    //                 }
+    //                 thread::sleep(Duration::from_millis(delay));
+    //             }
+    //         }
+    //     });
+    // }
 
+    /// Compute the duration in ms between samples in a pattern
+    pub fn get_sample_spacing(&self, bpm: i32) -> u64 {
+        // dbg!(&self.resolution);
+        let res = self.resolution/2;
+        //calc ms delay - this is for 4/4
+        ((60000.0 / bpm as f32) / res as f32) as u64
+
+    }
+
+    pub fn play_ref(&self, device: &Arc<rodio::Device>, bpm: i32) {
+
+        // let pat_clone = Arc::new(self.clone());
+        let pat_clone = self.clone();
         let device = device.clone();
-        // let device = device.clone();
-        let delay = ((60.0 / bpm as f32)*1000.0) as u64;
+        let delay = self.get_sample_spacing(bpm);
         
+        let snds = self.snds.clone();
         thread::spawn(move || {
             
             // loop for repeats
-
             for _ in 0..pat_clone.repeat + 1 {
                 for x in 0..pat_clone.xsize {
                     for y in 0..pat_clone.ysize {
                         let device = device.clone();
-                        if let Some(s) = pat_clone.sounds.get(&(x, y)) {
-                            // s.play(&device);
-                            
+                        if let Some(s) = snds.lock().unwrap().get(&(x, y)) {
+                        // if let Some(s) = pat_clone.sounds.get(&(x, y)) {
                             let s = s.clone();
                             thread::spawn(move || {
-
                                 s.play(&device, bpm);
-
-                                // if s.roll == 0 {
-                                //     s.play(&device, bpm);
-                                // } else {
-                                //     // let bpm = self.bpm;
-                                //     s.play_rolled(&device, bpm);
-                                // }
-                            
-
-
                             });
 
                         }
@@ -278,25 +316,13 @@ impl Pattern {
                 }
             }
         });
-        
-
-
-        // for _ in 0..self.repeat + 1 {
-        //     for x in 0..self.xsize {
-        //         for y in 0..self.ysize {
-        //             if let Some(s) = self.sounds.get(&(x, y)) {
-        //                 s.play(device);
-        //             }
-        //         }
-        //         thread::sleep(Duration::from_millis(delay));
-        //     }
-        // }
-
     }
 
-    pub fn duration(&self, bpm: i32) -> u64 {
-        ((60.0 / bpm as f32)*1000.0) as u64 * self.xsize as u64
 
+    /// Get the pattern duration in ms
+    pub fn duration(&self, bpm: i32) -> u64 {
+        self.get_sample_spacing(bpm) * self.xsize as u64
+        // ((60.0 / bpm as f32)*1000.0) as u64 * self.xsize as u64
     }
 
     /// Deserialize a pattern from a file.
@@ -304,8 +330,14 @@ impl Pattern {
         match File::open(file) {
             Ok(f) => {
                 serde_json::from_reader(BufReader::new(f))
-                    .map_err(|e| e.to_string())
-                    .map(|mut p: Pattern| p.reload_sounds( ))
+                    .map_err(|e| {
+                        dbg!(&e);
+                        e.to_string()
+                    })
+                    .map(|mut p: Pattern| p.reload_sounds())
+                    .map(|p| {
+                        println!("LD {} TMG {}", p.name, p.resolution);
+                        p})
             }
             Err(e) => Err(e.to_string())
         }
@@ -315,7 +347,8 @@ impl Pattern {
     /// This only replaces the source, leaving other settings intact.
     pub fn replace_sound_sources(&mut self, new_sound: &Sound, row: usize) {
         for x in 0..self.xsize {
-            if let Some(snd) = self.sounds.get_mut(&(x, row)) {
+            if let Some(snd) = self.snds.lock().unwrap().get_mut(&(x, row)) {
+                info!("replacing {} with {}", snd.name, new_sound.name);
                 snd.location = new_sound.location.clone();
                 snd.data = new_sound.data.clone();
             }
@@ -323,6 +356,34 @@ impl Pattern {
         }
     }
 
+    /// Insert a sound
+    pub fn insert_sound(&mut self, pos: &(usize, usize), snd: &Sound) {
+        self.snds.lock().unwrap().insert(*pos, snd.clone());
+    }
+
+    /// Remove a sound
+    pub fn remove_sound(&mut self, pos: &(usize, usize)) {
+        self.snds.lock().unwrap().remove(pos);
+    }
+
+    /// Check if a pattern contains a sound
+    pub fn contains_sound(&self, pos: &(usize, usize)) -> bool {
+        self.snds.lock().unwrap().contains_key(pos)
+    }
+
+    /// Return a MutexGuard to the sounds
+    pub fn sounds(&self) -> MutexGuard<HashMap<(usize, usize), Sound>> {
+        self.snds.lock().unwrap()
+    }
+
+    /// Get a sound from a pattern
+    pub fn get_sound(&self, pos: &(usize, usize)) -> Option<Sound> {
+        self.snds.lock().unwrap()
+            .get(pos)
+            .map(|s| s.clone())
+    }
+
+
     /// Replace all souds in a row by a new sound.
     /// This only replaces the source, leaving other settings intact.
     pub fn replace_sounds(&mut self, new_sound: &Sound, row: usize) {
@@ -339,13 +400,12 @@ impl Pattern {
         let mut names: HashMap<String, usize> = HashMap::new();
 
         for x in 0..self.xsize {
-            if let Some(snd) = self.sounds.get(&(x, row)) {
+            if let Some(snd) = self.snds.lock().unwrap().get(&(x, row)) {
                 match names.get_mut(&snd.name) {
                     Some(v) => *v += 1,
                     None => {names.insert(snd.name.clone(), 1);},
                 }
-        }
-        
+            }
         }
         let mut count_vec: Vec<_> = names.iter().collect();
         count_vec.sort_by(|a, b| b.1.cmp(a.1));
@@ -363,17 +423,15 @@ impl Pattern {
     }
 
     /// Clear all sound in a pattern row
-    pub fn clear_sounds(&mut self, row: usize) {
+    pub fn clear_row(&mut self, row: usize) {
         for x in 0..self.xsize {
-            if let Some(_) = self.sounds.get(&(x, row)) {
-                self.sounds.remove(&(x, row));
-            }
+            self.remove_sound(&(x, row));
         }
     }
 
     /// Clear all sounds in a pattern.
-    pub fn clear_all_sounds(&mut self) {
-        self.sounds.clear();
+    pub fn clear_all(&mut self) {
+        self.snds.lock().unwrap().clear();
     }
 
     /// Reload all sounds in a pattern
@@ -389,6 +447,7 @@ impl Pattern {
                 }
             }
         }
+        self.snds = Arc::new(Mutex::new(self.sounds.clone()));
         self.clone()
     }
 
@@ -407,20 +466,24 @@ impl Pattern {
         self.ysize = self.ysize+rows;
     }
 
-
 }
 
 #[derive(Clone, Debug)]
 pub struct Timeline {
-    pub patterns: Vec<Pattern>,
-    pub bpm: i32
+    pub bpm: i32,
+    pub xsize: usize,
+    pub ysize: usize,
+    pub patterns: HashMap<(usize, usize), Pattern>,
+
 }
 
 impl Default for Timeline {
     fn default() -> Timeline {
         Timeline {
-            patterns: vec![Pattern::default()],
-            bpm: 120
+            bpm: 120,
+            xsize: 8,
+            ysize: 1,
+            patterns: HashMap::new()
         }
     }
 }

+ 79 - 43
src/main.rs

@@ -12,8 +12,10 @@ use walkdir::WalkDir;
 mod support_ogl;
 // mod support_glium;
 use env_logger;
+use env_logger::Env;
 use std::sync::Arc;
-// use log::*;
+use std::sync::Mutex;
+use log::*;
 
 fn collect_sounds (root: &str) -> Vec<Sound> {
     WalkDir::new(root)
@@ -37,9 +39,19 @@ fn collect_patterns (root: &str) -> Vec<Pattern> {
     .collect()
 }
 
+fn brighten(col: [f32; 4] ) -> [f32; 4] {
+    let fac = 2.2;
+    [col[0]*fac, col[1]*fac, col[2]*fac, col[3]*fac]
+}
+
 fn main() {
 
-    env_logger::init();
+    // env_logger::init();
+    env_logger::from_env(Env::default().default_filter_or("info")).init();
+    info!("Starting");
+    // env_logger::builder()
+    // .format_timestamp(None)
+    // .init();
     // let dev = rodio::default_output_device().unwrap();
     let dev = Arc::new(rodio::default_output_device().unwrap());
     
@@ -52,14 +64,13 @@ fn main() {
     let mut pattern_col: usize = 0;
     let mut pattern_row: usize = 0;
     
-    let mut active_pattern = Pattern::default();
+    let mut active_pattern = Arc::new(Mutex::new(Pattern::default()));
+    let mut active_pattern = active_pattern.lock().unwrap();
     // let mut active_pattern = Arc::new(Pattern::default());
     let mut active_sound: Option<Sound> = None;
 
     let mut system = support_ogl::init(file!());
     let display = system.imgui.io().display_size;
-    let pixel_count = display[0]*display[1];
-    dbg!(pixel_count);
     let mut style = system.imgui.style_mut();
     style.window_rounding = 1.5;
     style.anti_aliased_lines = false;
@@ -125,11 +136,11 @@ fn main() {
                         ui.tree_node(&im_str!("{}", p.name)).build(|| {
                             // ui.same_line(0.0);
                             if ui.small_button(im_str!("load")) {
-                                active_pattern = p.clone();
+                                *active_pattern = p.clone();
                             }
                             ui.same_line(0.0);
                             if ui.small_button(im_str!("play")) {
-                                p.play(&dev, bpm);
+                                p.play_ref(&dev, bpm);
                             }
                         });
                     }
@@ -140,22 +151,16 @@ fn main() {
         Window::new(im_str!("pattern"))
             .size([300.0, 100.0], Condition::FirstUseEver)
             .build(ui, || {
+                let button_size: f32 = 32.0;
 
                 if ui.small_button(&im_str!("increase length")) {active_pattern.extend_length(1);}
                 ui.same_line(0.0);
                 if ui.small_button(&im_str!("add trk")) {active_pattern.extend_row(1);}
                 ui.same_line(0.0);
                 if ui.small_button(&im_str!("save")) {active_pattern.save();}
-                ui.same_line(0.0);
-                if ui.small_button(&im_str!("load")) {}
-                // if ui.small_button(&im_str!("theme")) {
-                //     let col: Vec<[f32; 4]> = style.clone().colors.iter().map(|x| x.clone()).collect();
-                //     let s = Theme {colors: col};
-                //     dbg!(&s);
-
-                // }
+     
 
-    
+                // The pattern name
                 let mut imstr_name = ImString::from(active_pattern.name.clone());
                 if ui.input_text(&im_str!("name"), &mut imstr_name)
                     .resize_buffer(true)
@@ -164,75 +169,96 @@ fn main() {
                     active_pattern.name = imstr_name.to_string();
                 };
                 
-                let button_size: f32 = 0.0;
+                ui.drag_int(im_str!("beats/bar"), &mut active_pattern.resolution)
+                    .max(64)
+                    .speed(0.1)
+                    .build();
 
                 ui.drag_int(im_str!("repeat"), &mut active_pattern.repeat)
                     .max(32)
                     .speed(0.05)
                     .build();
-                
 
+                // The grid header labels
+                
                 ui.text(im_str!("loc     "));
                 for x in 0..active_pattern.xsize {
                     ui.same_line(0.0);
-                    ui.button(&im_str!("{}", x+1), [button_size, button_size]);
+                    if x%4 == 0 {
+                        let s = ui.push_style_color(StyleColor::Button, brighten(PURPLE));
+                        ui.button(&im_str!("{}", x+1), [button_size, button_size]);
+                        s.pop(&ui);                
+
+                    } else {
+
+                        ui.button(&im_str!("{}", x+1), [button_size, button_size]);
+                    }
                 }
-                
 
+                // Loop over the length of the pattern
                 for y in 0..active_pattern.ysize {
                     ui.text(im_str!("{}", active_pattern.name_from_row(y)));
                     for x in 0..active_pattern.xsize {
-                        let label = match &active_pattern.sounds.get(&(x,y)) {
-                            Some(_s) => "X",
-                            None => " "
-                        };
+                        let snd = active_pattern.get_sound(&(x,y));
+                        
+                        let mut label = " ";
+                        
+
+                        match snd {
+                            Some(s) => {
+                                label = "X";
+                                if *s.active.lock().unwrap() {
+                                    label = "-"
+                                }
+                            },
+                            None => {}
+                        }
                         
                         ui.same_line(0.0);
                         if ui.button(&im_str!("{}##{}{}", label, y, x), [button_size, button_size]) {
-
                             pattern_col = x;
                             pattern_row = y;
                             match &active_sound {
-                                Some(snd) => {active_pattern.sounds.insert((x,y),  snd.clone());},
-                                None => {active_pattern.sounds.remove(&(x,y));}
+                                Some(snd) => active_pattern.insert_sound(&(x,y),  &snd),
+                                None => active_pattern.remove_sound(&(x,y))
                             }
-                        
-
                         }
                         // Convenience: remove items on right click
                         if ui.is_item_clicked(MouseButton::Right) {
-                            active_pattern.sounds.remove(&(x,y));
+                            active_pattern.remove_sound(&(x,y));
                         }
-                        
                     }
                     
                     ui.same_line(0.0);
                     if ui.small_button(&im_str!("replace src##{}",y) ){
                         if let Some(acs) = &active_sound {
+                            info!("{:?} {}", acs.location, acs.name);
                             active_pattern.replace_sound_sources(acs, y);
                         }
                     }
+
                     ui.same_line(0.0);
                     if ui.small_button(&im_str!("clr##{}", y) ){
-                        active_pattern.clear_sounds(y);
+                        active_pattern.clear_row(y);
                     }
-
-
                 }
 
                 ui.text(im_str!("pat {} {}", pattern_col, pattern_row));
                 if ui.small_button(&im_str!("play")) {
-                    active_pattern.play(&dev, bpm);
+                    active_pattern.play_ref(&dev, bpm);
+                    //active_pattern.play(&dev, bpm);
                 }
-
-        
             });
     
             Window::new(im_str!("sound"))
             .size([300.0, 100.0], Condition::FirstUseEver)
             .build(ui, || {
+
+                // let w = ui.current_column_width()*2.0/3.0 + 2.0;
+                let w = -1.0;
                 // check if active sounds is some
                 if let Some(s) = &mut active_sound {
+
                     ui.text(im_str!("name   {}", s.name));
 
                     ui.drag_float(im_str!("volume"), &mut s.volume)
@@ -264,8 +290,9 @@ fn main() {
                         .max(32)
                         .speed(0.01)
                         .build();
+                    ui.checkbox(im_str!("reverse"), &mut s.reverse);
                         
-                    if ui.small_button(&im_str!("adjust speed to pattern")) {
+                    if ui.button(&im_str!("adjust speed to pattern"), [w, 0.0]) {
                         if let Some(sd) = s.duration() {
                             let ad = active_pattern.duration(bpm);
                             dbg!(&sd.as_millis());
@@ -276,13 +303,12 @@ fn main() {
                         // dbg!(&l);
                         // let bpm = active_pattern.bpm;
                     }
-                    ui.checkbox(im_str!("reverse"), &mut s.reverse);
                 
-                    if ui.small_button(&im_str!("play")) {s.play(&dev, bpm)}
+                    if ui.button(&im_str!("play"), [w, 0.0]) {s.play(&dev, bpm)}
                 
                 }
 
-                if ui.small_button(&im_str!("clear")) {active_sound = None}
+                if ui.button(&im_str!("clear"), [w, 0.0]) {active_sound = None}
             });
     
 
@@ -298,9 +324,19 @@ fn main() {
                 .speed(0.01)
                 .build();
                
-                if ui.small_button(&im_str!("add")) {
-                    active_pattern.play(&dev, bpm);
+
+                if ui.small_button(&im_str!("add current pattern")) {
+                    // active_pattern.play(&dev, bpm);
+                }
+
+                if ui.small_button(&im_str!("play")) {
+                    active_pattern.play_ref(&dev, bpm);
                 }
+
+                // let k = Key::Space;
+                // if ui.is_key_released(k as u32) {
+                //     dbg!("GO");
+                // }
             });