def __init__(self, ins_num, mport, key, scale, octave=1, speed=1): super(DrumDeviator, self).__init__(ins_num, mport, key, scale, octave, speed) self.type = "Drum Deviator" self.height = 8 self.fire_chances = [0 for x in range(8)] self.transpose_chances = [0 for x in range(8)] self.temp_page = Note_Grid( self.bars, self.height) # Temporary page used for upcoming notes self.pages = [Note_Grid(self.bars, self.height)]
def load(self, saved): self.load_default_info(saved) self.sustain = saved["sustain"] self.random_pages = saved["random_rpt"] self.pages = [] for p in saved["pages"]: page = Note_Grid(self.bars, self.height) page.load(p) self.pages.append(page) return
def add_page(self, pos=True): '''Add or insert a new blank page into the list of pages''' if len(self.pages) == 16: lcd.flash("Max pages reached") return False if pos: self.pages.insert(self.curr_page_num + 1, Note_Grid(self.bars, self.height)) else: self.pages.append(Note_Grid(self.bars, self.height)) lcd.flash("Added page") return True
def load(self, saved): self.load_default_info(saved) self.sustain = saved["sustain"] self.random_pages = saved["random_rpt"] self.pages = [] for p in saved["pages"]: page = Note_Grid(self.bars, self.height) page.load(p) self.pages.append(page) self.densities = saved["densities"] self.offsets = saved["offsets"] self.lengths = saved["lengths"] self.curr_notes_pos = saved["curr_notes_pos"] return
def __init__(self, ins_num, mport, key, scale, octave=1, speed=1): super(Octopus, self).__init__(ins_num, mport, key, scale, octave, speed) self.type = "Octopus" self.bars = 4 self.pages = [Note_Grid(self.bars, self.height)] self.densities = [0 for x in range(8)]
def __init__(self, ins_num, mport, key, scale, octave=1, speed=1): super(Sequencer, self).__init__(ins_num, mport, key, scale, octave, speed) self.type = "Sequencer" self.bars = 4 # min(bars, W/4) # Option to reduce number of bars < 4 self.curr_page_num = 0 self.curr_rept_num = 0 self.prev_loc_beat = 0 self.local_beat_position = 0 self.random_pages = False # Pick page at random self.sustain = True # Don't retrigger notes if this is True self.pages = [Note_Grid(self.bars, self.height)] OLED_Screens = proxy_registry('OLED_Screens')
def __init__(self, ins_num, mport, key, scale, octave=1, speed=1): super(DrumMachine, self).__init__(ins_num, mport, key, scale, octave, speed) self.type = "Drum Machine" self.is_drum = True self.bars = 4 self.curr_page_num = 0 self.curr_rept_num = 0 self.prev_loc_beat = 0 self.local_beat_position = 0 self.random_pages = False # Pick page at random self.sustain = False # Don't retrigger notes if this is True self.pages = [Note_Grid(self.bars, self.height)] self.key = 'c' # TODO find which starting note corresponds to pad 0 self.scale = 'chromatic' self.octave = 1 # Starting octave self.old_notes = [ ] # Keep track of currently playing notes so we can off them next step self.note_converter = create_cell_to_midi_note_lookup( self.scale, self.octave, self.key, self.height)
class DrumDeviator(DrumMachine): """Drum Deviator - Random Deviation Beat Sequencer - Draw a beat on a sequencer grid - Each drum-note/sample has a separate random chance of suppressing/firing or transposing - Show drum sequencer along bottom 16x8, with notes that are modified for this bar highlighted - (suppressed: slightly darker - triggered: slightly brighter - transposed: different color) - Use the top 16x8 for controls like randomness per note - Allow multiple pages per instrument - Transposition could/should be predictable, eg to +8 notes - Random notes for each bar determined at start of bar - Randomness/chaos amount should be per bar, not per note. eg: at low levels, only change a few notes occasionally - TODO randomness controls cover all pages - maybe they should be per-page? - TODO apply_randomness doesn't show effects on LED grid - TODO maybe fire chance shouldn't add notes randomly, only add where there are already other notes""" def __init__(self, ins_num, mport, key, scale, octave=1, speed=1): super(DrumDeviator, self).__init__(ins_num, mport, key, scale, octave, speed) self.type = "Drum Deviator" self.height = 8 self.fire_chances = [0 for x in range(8)] self.transpose_chances = [0 for x in range(8)] self.temp_page = Note_Grid( self.bars, self.height) # Temporary page used for upcoming notes self.pages = [Note_Grid(self.bars, self.height)] # each time page changes/restarts, calculate random chance of _either_: # suppressing active note # firing quiet note # transposing active note # calculated on a per note basis # Keep original beat pattern intact for next page # show changed notes in different colors # two highlighted sets of 8 sliders for fire/suppress and transpose (centre-out? zero lit) # Use regular note_grid to save originals, only 8 high # Each new page, generate a temp page of notes (16 high) based on calculations # But display 8x16 notes and mods def apply_control(self, x, y): if y >= 8: # Control touch, but save it in the page, it's easier that way y -= 8 if x < 8: # Fire chances self.fire_chances[y] = 7 - x else: # Transpose chances self.transpose_chances[y] = x - 8 def touch_note(self, state, x, y): '''touch the x/y cell on the current page - either a control, or a note''' if state == 'play': # Is touch control or note? self.apply_control(x, y) # Apply touch to current temp page and source page self.get_curr_page().touch_note(x, y) self.temp_page.touch_note(x, y) elif state == 'ins_cfg': cb_text, _x, _y = get_cb_from_touch(self.cb_grid, x, y) if not cb_text: return cb_func = self.__getattribute__( 'cb_' + cb_text) # Lookup the relevant conductor function cb_func( _x, _y) # call it, passing it x/y args (which may not be needed) return True def get_led_grid(self, state): if state == 'play': led_grid = [] grid = self.get_curr_page().note_grid for i, column in enumerate(grid): led_grid.append([self.get_led_status(x, i) for x in column]) # Draw control sliders for y in range(8): # reset slider area (removes beat cursor) for x in range(16): led_grid[x][y + 8] = c.LED_BLANK for a in range(self.fire_chances[y] + 1): led_grid[7 - a][y + 8] = c.LED_ACTIVE led_grid[7 - self.fire_chances[y]][y + 8] = c.LED_SELECT led_grid[7][y + 8] = c.LED_CURSOR for a in range(self.transpose_chances[y]): led_grid[8 + a][y + 8] = c.LED_ACTIVE led_grid[8 + self.transpose_chances[y]][y + 8] = c.LED_SELECT led_grid[8][y + 8] = c.LED_CURSOR elif state == 'ins_cfg': led_grid, cb_grid = generate_screen( dev_cfg_grid_defn, { 'speed': int(self.speed), 'octave': int(self.octave), 'pages': [x.repeats for x in self.pages], 'curr_p_r': (self.curr_page_num, self.curr_rept_num), 'curr_page': self.curr_page_num, 'next_page': self.get_next_page_num() }) self.cb_grid = cb_grid return led_grid return led_grid def advance_page(self): '''Go to next repeat or page''' if self.random_pages: # Create a distribution of the pages and their repeats, pick one at random dist = [] for index, page in enumerate(self.pages): for r in range(page.repeats): dist.append(index) next_page_num = choice(dist) self.curr_page_num = next_page_num self.curr_rept_num = 0 # Reset, for this page or next page return self.curr_rept_num += 1 # inc repeat number if self.curr_rept_num >= self.get_curr_page().repeats: # If we're overfowing repeats, time to go to next available page self.curr_rept_num = 0 # Reset, for this page or next page self.curr_page_num = self.get_next_page_num() self.selected_next_page_num = None # Take control figures from new page, apply to controls notes = self.get_curr_page().note_grid for y in range(8, 16): for x in range(16): if notes[x][y] == c.NOTE_ON: self.apply_control(x, y) self.apply_randomness() return def apply_randomness(self): '''Page has turned, apply randomness using source page onto temp page''' self.temp_page.note_grid = deepcopy(self.get_curr_page().note_grid) for x, beat in enumerate(self.temp_page.note_grid): # For each beat for y, note in enumerate(beat[:8]): # For each note in beat fire = self.calc_chance(self.fire_chances[y]) if fire: note = c.NOTE_ON if note == c.NOTE_OFF else c.NOTE_OFF self.temp_page.note_grid[x][y] = note if note == c.NOTE_ON: if self.calc_chance(self.transpose_chances[y]): self.temp_page.note_grid[x][y + 8] = c.NOTE_ON self.temp_page.note_grid[x][y] = c.NOTE_OFF return def calc_chance(self, chance): '''chance is int between 0 and 8''' choices = [True] * chance + [False] * (20 - chance) c = choice(choices) return c def save(self): saved = { "pages": [p.save() for p in self.pages], "sustain": self.sustain, "random_rpt": self.random_pages, "fire_chances": self.fire_chances, "transpose_chances": self.transpose_chances, } saved.update(self.default_save_info()) return saved def load(self, saved): self.load_default_info(saved) self.sustain = saved["sustain"] self.random_pages = saved["random_rpt"] self.pages = [] self.fire_chances = saved['fire_chances'] self.transpose_chances = saved['transpose_chances'] for p in saved["pages"]: page = Note_Grid(self.bars, self.height) page.load(p) self.pages.append(page) return