-
Notifications
You must be signed in to change notification settings - Fork 0
/
DrumsBeatColorer.py
130 lines (106 loc) · 4.27 KB
/
DrumsBeatColorer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from __future__ import annotations
from MusiStrata.Components.Structure import Bar, Track
from MusiStrata.Components.Notes import Note
from MusiStrata.Drums import GetHeightFromDrumsInstrumentName
from copy import deepcopy
from typing import Dict, List
def GetNoteFromDrumInstrument(drumInstrument: str) -> Note:
height = GetHeightFromDrumsInstrumentName(drumInstrument)
outNote = Note.FromHeight(height)
return outNote
class DrumsBeatColorer(object):
"""
Create a DrumsBeatColorer from definitions of beat and instruments.
This class allows to set a particular instrument to notes in a Drums track.
It works by specifying types of beats (primary, secondary...) and associating instruments
in the definition. Doing it this way allows a given beat to have several drums acting on it if so desired
NOTE: Will only support instruments defined as DRUMS in MusiStrata.Drums
Drums have their own specific channel
Example Input
{
"Name": "TestBeats",
"Tags": ["Test"],
"NbBeats": 4,
"BeatsDecomposition": {
"Primary": [0.0],
"Secondary": [0.0, 2.0]
},
"DrumsInstruments": {
"Primary": "Bass Drum 1",
"Secondary": "High Tom 1",
"Default": "Snare Drum 1"
}
}
"""
def __init__(self, specs: Dict):
# Dicts are mutable so DO NOT SET THEM as cls property
self.BeatsValueToBeatsClassified = {}
self.DrumsInstruments = {}
self.DrumsInstruments = specs["DrumsInstruments"]
self.SetBeatsDecomposition(specs["BeatsDecomposition"])
def SetBeatsDecomposition(self, beatsDecomposition: Dict) -> None:
"""
beatsDecomposition in the specs json to be input maps keys to arrays of beats, to make it easy
to specify new presets for the user.
Here we reverse this: a beat can be both primary and secondary, and more depending on the specs
So we create a new dict using the beat as key, and its classifications in an array
Example:
{
"Primary": [0.0],
"Secondary": [0.0, 2.0]
}
will become:
{
0.0: ["Primary", "Secondary"],
2.0: ["Secondary"]
}
NOTE: 0.0 and 0 are considered the same thing when used as key in a dict
"""
self.BeatsValueToBeatsClassified = {}
for key in list(beatsDecomposition.keys()):
for val in beatsDecomposition[key]:
if val in list(self.BeatsValueToBeatsClassified.keys()):
self.BeatsValueToBeatsClassified[val].append(key)
else:
self.BeatsValueToBeatsClassified[val] = [key]
def CheckInstrumentsForBeat(self, beat: float) -> List[str]:
"""
get the instruments to be associated with a given beat
:param beat: float
:return: List[str], a list of instrument names
"""
if beat in list(self.BeatsValueToBeatsClassified.keys()):
beatCategories = self.BeatsValueToBeatsClassified[beat]
if type(beatCategories) != list:
beatCategories = [beatCategories]
outInstruments = [
self.DrumsInstruments[
cat
] for cat in beatCategories
]
else:
outInstruments = self.DrumsInstruments["Default"]
if type(outInstruments) != list:
outInstruments = [outInstruments]
return outInstruments
def PrepareBar(self, inputBar: Bar) -> Bar:
newBar = Bar()
for se in inputBar.SoundEvents:
noteInstruments = self.CheckInstrumentsForBeat(se.Beat)
for instrument in noteInstruments:
newSoundEvent = deepcopy(se)
newSoundEvent.Note = GetNoteFromDrumInstrument(instrument)
newBar.SoundEvents.append(newSoundEvent)
return newBar
def PrepareTrack(self, track: Track) -> None:
"""
Set drums instruments to notes, depending on beat
"""
newBars = []
for bar in track.Bars:
newBars.append(
self.PrepareBar(
bar
)
)
track.Bars = newBars