def on_zyncoder(self, encoder, value): if encoder == ENC_BACK: if self.edit_mode: self.velocity = self.velocity + value if self.velocity > 127: self.velocity = 127 return if self.velocity < 1: self.velocity = 1 return self.velocity_canvas.coords( "velocityIndicator", 0, 0, self.piano_roll_width * self.velocity / 127, PLAYHEAD_HEIGHT) note = self.keymap[self.selected_cell[1]]["note"] if libseq.getNoteDuration(self.selected_cell[0], note): libseq.setNoteVelocity(self.selected_cell[0], note, self.velocity) self.draw_cell(self.selected_cell[0], self.selected_cell[1]) self.parent.set_title("Velocity: %d" % (self.velocity), None, None, 2) else: self.select_cell(None, self.selected_cell[1] - value) elif encoder == ENC_SELECT: if self.edit_mode: if value > 0: self.duration = self.duration + 1 if value < 0: self.duration = self.duration - 1 if self.duration > libseq.getSteps(): self.duration = libseq.getSteps() return if self.duration < 1: self.duration = 1 return if libseq.getNoteDuration(self.selected_cell[0], self.selected_cell[1]): self.add_event(self.selected_cell[0], self.selected_cell[1]) else: self.select_cell() self.parent.set_title("Duration: %d steps" % (self.duration), None, None, 2) else: self.select_cell(self.selected_cell[0] + value, None) elif encoder == ENC_LAYER and not self.parent.lst_menu.winfo_viewable( ): # Show menu self.parent.toggle_menu() return
def test_ac08_copy_pattern(self): libseq.selectPattern(999) libseq.addNote(0, 60, 123, 2) libseq.copyPattern(999, 998) libseq.selectPattern(998) self.assertEqual(libseq.getNoteDuration(0, 60), 2) self.assertEqual(libseq.getNoteVelocity(0, 60), 123)
def draw_cell(self, step, row): libseq.isPatternModified() # Avoid refresh redrawing whole grid cellIndex = row * libseq.getSteps( ) + step # Cells are stored in array sequentially: 1st row, 2nd row... if cellIndex >= len(self.cells): return note = self.keymap[row + self.keymap_offset]["note"] velocity_colour = libseq.getNoteVelocity(step, note) if velocity_colour: velocity_colour = 70 + velocity_colour elif libseq.getScale() == 1: # Draw tramlines for white notes in chromatic scale key = note % 12 if key in (0, 2, 4, 5, 7, 9, 11): # White notes # if key in (1,3,6,8,10): # Black notes velocity_colour += 30 else: # Draw tramlines for odd rows in other scales and maps if (row + self.keymap_offset) % 2: velocity_colour += 30 duration = libseq.getNoteDuration(step, note) if not duration: duration = 1 fill_colour = "#%02x%02x%02x" % (velocity_colour, velocity_colour, velocity_colour) cell = self.cells[cellIndex] coord = self.get_cell(step, row, duration) if cell: # Update existing cell self.grid_canvas.itemconfig(cell, fill=fill_colour) self.grid_canvas.coords(cell, coord) else: # Create new cell cell = self.grid_canvas.create_rectangle( coord, fill=fill_colour, width=0, tags=("%d,%d" % (step, row), "gridcell", "step%d" % step)) self.grid_canvas.tag_bind(cell, '<ButtonPress-1>', self.on_grid_press) self.grid_canvas.tag_bind(cell, '<ButtonRelease-1>', self.on_grid_release) self.grid_canvas.tag_bind(cell, '<B1-Motion>', self.on_grid_drag) self.cells[cellIndex] = cell if step + duration > libseq.getSteps(): self.grid_canvas.itemconfig("lastnotetext%d" % row, text="+%d" % (duration - libseq.getSteps() + step), state="normal")
def export_smf(self, params): smf = libsmf.addSmf() tempo = libseq.getTempo() libsmf.addTempo(smf, 0, tempo) ticks_per_step = libsmf.getTicksPerQuarterNote( smf) / libseq.getStepsPerBeat() for step in range(libseq.getSteps()): time = int(step * ticks_per_step) for note in range(128): duration = libseq.getNoteDuration(step, note) if duration == 0: continue duration = int(duration * ticks_per_step) velocity = libseq.getNoteVelocity(step, note) libsmf.addNote(smf, 0, time, duration, self.channel, note, velocity) libsmf.setEndOfTrack(smf, 0, int(libseq.getSteps() * ticks_per_step)) zynsmf.save( smf, "/zynthian/zynthian-my-data/capture/pattern%d_%s.mid" % (self.pattern, datetime.now()))
def on_grid_press(self, event): if self.parent.lst_menu.winfo_viewable(): self.parent.hide_menu() return if self.parent.param_editor_item != None: self.parent.hide_param_editor() return self.grid_drag_start = event try: col, row = self.grid_canvas.gettags( self.grid_canvas.find_withtag(tkinter.CURRENT))[0].split(',') except: return note = self.keymap[self.keymap_offset + int(row)]["note"] step = int(col) if step < 0 or step >= libseq.getSteps(): return self.drag_start_velocity = libseq.getNoteVelocity(step, note) self.drag_start_duration = libseq.getNoteDuration(step, note) self.drag_start_step = int(event.x / self.step_width) if not self.drag_start_velocity: self.play_note(note) self.select_cell(int(col), self.keymap_offset + int(row))
def select_cell(self, step=None, index=None): if len(self.keymap) == 0: return redraw = False if step == None: step = self.selected_cell[0] if index == None: index = self.selected_cell[1] if step < 0: step = 0 if step >= libseq.getSteps(): step = libseq.getSteps() - 1 if index >= len(self.keymap): index = len(self.keymap) - 1 if index >= self.keymap_offset + self.zoom: # Note is off top of display self.keymap_offset = index - self.zoom + 1 redraw = True if index < 0: index = 0 if index < self.keymap_offset: # Note is off bottom of display self.keymap_offset = index redraw = True if redraw: self.redraw_pending = 1 row = index - self.keymap_offset note = self.keymap[index]['note'] # Skip hidden (overlapping) cells for previous in range(step - 1, -1, -1): prev_duration = libseq.getNoteDuration(previous, note) if not prev_duration: continue if prev_duration > step - previous: if step > self.selected_cell[0]: step = previous + prev_duration else: step = previous break if step < 0: step = 0 if step >= libseq.getSteps(): step = libseq.getSteps() - 1 self.selected_cell = [step, index] cell = self.grid_canvas.find_withtag("selection") duration = libseq.getNoteDuration(step, row) if not duration: duration = self.duration coord = self.get_cell(step, row, duration) coord[0] = coord[0] - 1 coord[1] = coord[1] - 1 coord[2] = coord[2] coord[3] = coord[3] if not cell: cell = self.grid_canvas.create_rectangle( coord, fill="", outline=SELECT_BORDER, width=self.select_thickness, tags="selection") else: self.grid_canvas.coords(cell, coord) self.grid_canvas.tag_raise(cell)
def on_grid_drag(self, event): if not self.grid_drag_start: return step = self.selected_cell[0] index = self.selected_cell[1] note = self.keymap[index]['note'] if self.drag_start_velocity: # Selected cell has a note so we want to adjust its velocity or duration if not self.drag_velocity and not self.drag_duration and ( event.x > (self.drag_start_step + 1) * self.step_width or event.x < self.drag_start_step * self.step_width): self.drag_duration = True if not self.drag_duration and not self.drag_velocity and ( event.y > self.grid_drag_start.y + self.row_height / 2 or event.y < self.grid_drag_start.y - self.row_height / 2): self.drag_velocity = True value = 0 if self.drag_velocity: value = (self.grid_drag_start.y - event.y) / self.row_height if value: self.velocity = int(self.drag_start_velocity + value * self.height / 100) if self.velocity > 127: self.velocity = 127 return if self.velocity < 1: self.velocity = 1 return self.velocity_canvas.coords( "velocityIndicator", 0, 0, self.piano_roll_width * self.velocity / 127, PLAYHEAD_HEIGHT) if libseq.getNoteDuration(self.selected_cell[0], note): libseq.setNoteVelocity(self.selected_cell[0], note, self.velocity) self.draw_cell(self.selected_cell[0], index) if self.drag_duration: value = int(event.x / self.step_width) - self.drag_start_step duration = self.drag_start_duration + value if duration != self.duration and duration > 0: self.duration = duration self.add_event( step, index ) # Change length by adding event over previous one else: # Clicked on empty cell so want to add a new note by dragging towards the desired cell x1 = self.selected_cell[ 0] * self.step_width # x pos of start of event x3 = (self.selected_cell[0] + 1) * self.step_width # x pos right of event's first cell y1 = self.grid_height - ( self.selected_cell[1] - self.keymap_offset ) * self.row_height # y pos of top of selected row y2 = self.grid_height - ( self.selected_cell[1] - self.keymap_offset + 1) * self.row_height # y pos of bottom of selected row if event.x < x1: self.select_cell(self.selected_cell[0] - 1, None) elif event.x > x3: self.select_cell(self.selected_cell[0] + 1, None) elif event.y < y2: self.select_cell(None, self.selected_cell[1] + 1) self.play_note(self.keymap[self.selected_cell[1]]["note"]) elif event.y > y1: self.select_cell(None, self.selected_cell[1] - 1) self.play_note(self.keymap[self.selected_cell[1]]["note"])
def test_ac09_clear_pattern(self): libseq.clear() self.assertEqual(libseq.getNoteDuration(0, 65), 0)
def test_ac07_transpose(self): libseq.selectPattern(999) libseq.addNote(0, 60, 123, 2) libseq.transpose(5) self.assertEqual(libseq.getNoteDuration(0, 65), 2) self.assertEqual(libseq.getNoteVelocity(0, 65), 123)
def test_ac06_set_note_duration(self): libseq.selectPattern(999) libseq.addNote(0, 60, 123, 2) self.assertEqual(libseq.getNoteDuration(0, 60), 2)
def test_ac04_add_note_too_long(self): libseq.selectPattern(999) self.assertTrue(libseq.addNote(0, 60, 100, 4)) self.assertFalse(libseq.addNote(0, 60, 100, 200)) self.assertEqual(libseq.getNoteVelocity(0, 60), 100) self.assertEqual(libseq.getNoteDuration(0, 60), 4)