def __init__(self, other_members, tempo, bars, divs, inst_set): super(Session, self).__init__() self.tempo = tempo self.bars = bars self.divs = divs self.inst_set = inst_set spb = 60. / tempo beats = bars * 4 self.seconds = spb * beats self.clock = Clock() self.temp_map = SimpleTempoMap(bpm=tempo) self.sched = Scheduler(self.clock, self.temp_map) # self.players = players self.IM = InstrumentManager(self.sched) self.add(self.IM) ### NEW CODE ### self.pattern_list = PatternList(self.bars, self.tempo, self.inst_set) self.add(self.pattern_list) track = Track(num_lanes, self.bars, self.tempo) track.position.y = Window.height * 0.025 controller = InstrumentKeyboard(default_keycodes, lock_in_keycode) self.player = Player(controller, track, inst_set) self.player.position.x = Window.width - player_size[0] - 20 self.add(self.player) self.vplayers = [] self.add_band_members(other_members) self.IM.add(self.player.instrument) self.clock.offset = self.seconds - spb self.paused = True self.start()
def __init__(self, callback=None): super(DataPlayer, self).__init__() self.sched = Scheduler(Clock(), tempo_map=[(0, 0), (100000000000, 100000000000 / 60 * 480)]) self.beat_len = kTicksPerQuarter self.on_cmd = None self.off_cmd = None self.playing = False self.callback = None self.barData = None
def __init__(self, norm, pos, tempo, clock, tempo_map, touch_points, block_handler): super(TempoCursor, self).__init__() self.norm = norm self.pos = pos self.size = self.norm.nt((70, 70)) self.cursor = CEllipse(cpos=pos, csize=self.size) self.add(Color(1, 1, 1)) self.add(self.cursor) self.tempo = tempo self.clock = clock self.tempo_map = tempo_map self.sched = Scheduler(self.clock, self.tempo_map) self.block_handler = block_handler # 0..15, for 16th note granularity self.touch_points = touch_points self.index = 0 # add touch markers self.add(PushMatrix()) self.add(Translate(*pos)) for touch_point in self.touch_points: self.add(Rotate(angle=-360 * touch_point / 16)) self.add(Color(159 / 255, 187 / 255, 208 / 255)) # blue self.add(Line(points=(0, 0, 0, self.norm.nv(25)), width=2)) self.add(Rotate(angle=360 * touch_point / 16)) self.add(PopMatrix()) # add current time marker self.add(PushMatrix()) self.add(Translate(*pos)) self.time_marker = Line(points=(0, 0, 0, self.norm.nv(30)), width=3) self.rotate = Rotate(angle=0) self.add(self.rotate) self.add(Color(0, 0, 0)) self.add(self.time_marker) self.add(PopMatrix()) self.on_update(0) cur_tick = self.sched.get_tick() next_tick = quantize_tick_up(cur_tick, kTicksPerQuarter * 4) next_tick += self.calculate_tick_interval(0, self.touch_points[0]) self.sched.post_at_tick(self.touch_down, next_tick)
def __init__(self): super(MainWidget3, self).__init__() # create a clock and TempoMap self.clock = Clock() self.tempo = SimpleTempoMap(120) # create a Scheduler self.sched = Scheduler(self.clock, self.tempo) # and text to display our status self.label = topleft_label() self.add_widget(self.label) # to see accumulated output: self.output_text = ''
class MainWidget4(BaseWidget): def __init__(self): super(MainWidget4, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) # create clock, tempo_map, scheduler self.clock = Clock() self.tempo_map = SimpleTempoMap(120) self.sched = Scheduler(self.clock, self.tempo_map) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label) def on_key_down(self, keycode, modifiers): if keycode[1] == 'c': self.clock.toggle() if keycode[1] == 'm': self.metro.toggle() bpm_adj = lookup(keycode[1], ('up', 'down'), (10, -10)) if bpm_adj: new_tempo = self.tempo_map.get_tempo() + bpm_adj self.tempo_map.set_tempo(new_tempo, self.sched.get_time()) def on_update(self): # scheduler and audio get poked every frame self.sched.on_update() self.audio.on_update() bpm = self.tempo_map.get_tempo() self.label.text = self.sched.now_str() + '\n' self.label.text += 'Metronome:' + ("ON" if self.metro.playing else "OFF") + '\n' self.label.text += 'tempo:{}\n'.format(bpm) self.label.text += 'm: toggle Metronome\n' self.label.text += 'up/down: change speed\n'
def __init__(self): super(MainWidget4, self).__init__() self.audio = Audio(2) self.synth = Synth('../data/FluidR3_GM.sf2') self.audio.set_generator(self.synth) # create clock, tempo_map, scheduler self.clock = Clock() self.tempo_map = SimpleTempoMap(120) self.sched = Scheduler(self.clock, self.tempo_map) # create the metronome: self.metro = Metronome(self.sched, self.synth) # and text to display our status self.label = topleft_label() self.add_widget(self.label)
def __init__(self, songPattern, key, clock): self.slack_timout = beats_to_time(.5, self.bpm) self.gems, self.bars = self._initialize_bars(songPattern, key) self.synth = Synth('../bank/FluidR3_GM.sf2') totalBeats = self.measuresPerCall * self.numRepeats * len( self.bars) * 4 totalTime = beats_to_time(totalBeats, self.bpm) totalOffsetTicks = self.endBarTicks * totalBeats / 4 totalTicks = totalBeats / 4 * self.barLenTicks data = [(0, 0), ((totalTime + ticks_to_time(totalOffsetTicks, self.bpm)) * 2, totalTicks * 2)] self.tempo = TempoMap(data=data) self.num_bars = len(data) self.scheduler = Scheduler(clock, self.tempo) self.increment_bar = None self.catch_passes = None self.on_commands = [] # commands for a bar of call and response self.off_commands = [] self.active_gems = [] self.gem_commands = [] self.bar_tick = 0 self.bar_index = 0 print(songPattern)
class MainWidget3(BaseWidget): def __init__(self): super(MainWidget3, self).__init__() # create a clock and TempoMap self.clock = Clock() self.tempo = SimpleTempoMap(120) # create a Scheduler self.sched = Scheduler(self.clock, self.tempo) # and text to display our status self.label = topleft_label() self.add_widget(self.label) # to see accumulated output: self.output_text = '' def on_key_down(self, keycode, modifiers): if keycode[1] == 'c': self.clock.toggle() if keycode[1] == 'a': now = self.sched.get_tick() later = now + (2 * kTicksPerQuarter) self.output_text += "now={}. post at tick={}\n".format(now, later) self.cmd = self.sched.post_at_tick(self._do_it, later, 'hello') if keycode[1] == 'b': self.sched.remove(self.cmd) def _do_it(self, tick, msg): self.output_text += "{} (at {})\n".format(msg, tick) def on_update(self): # scheduler gets called every frame to process events self.sched.on_update() self.label.text = self.sched.now_str() + '\n' self.label.text += 'c: toggle clock\n' self.label.text += 'a: post event\n' self.label.text += 'b: remove event\n' self.label.text += self.output_text
class DataPlayer(object): """Plays a steady click every beat. """ def __init__(self, callback=None): super(DataPlayer, self).__init__() self.sched = Scheduler(Clock(), tempo_map=[(0, 0), (100000000000, 100000000000 / 60 * 480)]) self.beat_len = kTicksPerQuarter self.on_cmd = None self.off_cmd = None self.playing = False self.callback = None self.barData = None def start(self): if self.playing: return self.playing = True now = self.sched.get_tick() next_beat = quantize_tick_up(now, self.beat_len) self.on_cmd = self.sched.post_at_tick(self.tick, next_beat) def stop(self): if not self.playing: return self.playing = False if self.off_cmd: self.off_cmd.execute() self.sched.remove(self.on_cmd) self.sched.remove(self.off_cmd) self.on_cmd = None self.off_cmd = None # def set_bar(self, bar_data): # self.barData = bar_data def toggle(self): if self.playing: self.stop() else: self.start() def tick(self, tick, ignore): next_beat = tick + self.beat_len self.on_cmd = self.sched.post_at_tick(self.tick, next_beat) # class ScoreScreen(BaseWidget): # def __init__(self, scoreCard=ScoreCard(), callBack=None): # super(ScoreScreen, self).__init__() # w = Window.width//3 # buttonSize = (w, w//3) # buttonAnchor = (3*Window.width//4, Window.height//4) # self.scoreCard = scoreCard # titleString= "Score Card" # title = Rectangle(pos=(Window.width//4, 3*Window.height//4), size=(2*Window.width//4, Window.height//5)) # label = CoreLabel(text=titleString, font_size=56) # label.refresh() # text = label.texture # title.texture = text # self.objects = AnimGroup() # self.cards = self.generateTiles(self.scoreCard.getAllStrings()) # self.canvas.add(Rectangle(size=(Window.width,Window.height))) # self.canvas.add(self.objects) # self.canvas.add(Color(*(.05,.28,.1))) # self.canvas.add(title) # [self.objects.add(card) for card in self.cards] # print('ScoreScreen Initialized') # def generateTiles(self, scoreStrings): # print(scoreStrings) # xa,ya = (10,0) # x = xa # y = ya # padding = 10 # tile = Card(scoreStrings[0]) # w,h = tile.getSize() # outputs = [tile] # for i in range(1, len(scoreStrings)): # if i % 5 == 0: # y += h + padding # x = xa - w- padding # x += w + padding # outputs.append(Card(scoreStrings[i], pos=(x,y), size=(w,h))) # return outputs # def on_update(self): # self.objects.on_update() # # print('homescreenUpdate') # def on_key_down(self, keycode, modifiers): # pass # run(ScoreScreen)
class TempoCursor(InstructionGroup): """ This module is a timed cursor that creates touch_down events on any objects that it is placed over. It uses an underlying tempo that is room-wide. """ name = 'TempoCursor' def __init__(self, norm, pos, tempo, clock, tempo_map, touch_points, block_handler): super(TempoCursor, self).__init__() self.norm = norm self.pos = pos self.size = self.norm.nt((70, 70)) self.cursor = CEllipse(cpos=pos, csize=self.size) self.add(Color(1, 1, 1)) self.add(self.cursor) self.tempo = tempo self.clock = clock self.tempo_map = tempo_map self.sched = Scheduler(self.clock, self.tempo_map) self.block_handler = block_handler # 0..15, for 16th note granularity self.touch_points = touch_points self.index = 0 # add touch markers self.add(PushMatrix()) self.add(Translate(*pos)) for touch_point in self.touch_points: self.add(Rotate(angle=-360 * touch_point / 16)) self.add(Color(159 / 255, 187 / 255, 208 / 255)) # blue self.add(Line(points=(0, 0, 0, self.norm.nv(25)), width=2)) self.add(Rotate(angle=360 * touch_point / 16)) self.add(PopMatrix()) # add current time marker self.add(PushMatrix()) self.add(Translate(*pos)) self.time_marker = Line(points=(0, 0, 0, self.norm.nv(30)), width=3) self.rotate = Rotate(angle=0) self.add(self.rotate) self.add(Color(0, 0, 0)) self.add(self.time_marker) self.add(PopMatrix()) self.on_update(0) cur_tick = self.sched.get_tick() next_tick = quantize_tick_up(cur_tick, kTicksPerQuarter * 4) next_tick += self.calculate_tick_interval(0, self.touch_points[0]) self.sched.post_at_tick(self.touch_down, next_tick) def on_update(self, dt): self.sched.on_update() cur_time = self.sched.get_time() cur_tick = self.sched.get_tick() angle = (360 * (cur_tick / (kTicksPerQuarter * 4))) % 360 self.rotate.angle = -angle def calculate_tick_interval(self, p1, p2): if p2 > p1: return (p2 - p1) / 4 * kTicksPerQuarter elif p1 > p2: return (p2 + 16 - p1) / 4 * kTicksPerQuarter else: return 0 def round_to_sixteenth(self, tick): kTicksPerSixteenth = kTicksPerQuarter / 4 kTicksPerMeasure = kTicksPerQuarter * 4 measure = math.floor(tick / kTicksPerMeasure) beat = round(16 * ((tick % kTicksPerMeasure) / kTicksPerMeasure)) return measure * kTicksPerMeasure + (beat * kTicksPerSixteenth) def touch_down(self, tick): self._touch_down() cur_tick = self.round_to_sixteenth(self.sched.get_tick()) next_index = (self.index + 1) % len(self.touch_points) p1 = self.touch_points[self.index] p2 = self.touch_points[next_index] interval = kTicksPerQuarter * 4 if len(self.touch_points) == 1 \ else self.calculate_tick_interval(p1, p2) next_tick = cur_tick + interval self.index = next_index self.sched.post_at_tick(self.touch_down, next_tick) def _touch_down(self): for block in self.block_handler.blocks.objects: if in_bounds(self.pos, block.pos, block.size): block.flash()
class Ticker(object): ''' Maps beat patterns to ticks (time stamps) and plays the call of the call and response (if enabled) This class assumes quarter notes as beats. becase every loop in this game is 4 measures, we will assume a loop to last 16 beats. (4/4) ''' bpm = 400 numRepeats = 3 measuresPerCall = 1 channel = 0 vel = 80 playQueues = 1 noteDuration = 1 nowBarHeight = Window.height // 2 endBarTicks = kTicksPerQuarter * .5 barLenTicks = kTicksPerQuarter * 4 + endBarTicks gemRadius = 100 padding = gemRadius + 50 def __init__(self, songPattern, key, clock): self.slack_timout = beats_to_time(.5, self.bpm) self.gems, self.bars = self._initialize_bars(songPattern, key) self.synth = Synth('../bank/FluidR3_GM.sf2') totalBeats = self.measuresPerCall * self.numRepeats * len( self.bars) * 4 totalTime = beats_to_time(totalBeats, self.bpm) totalOffsetTicks = self.endBarTicks * totalBeats / 4 totalTicks = totalBeats / 4 * self.barLenTicks data = [(0, 0), ((totalTime + ticks_to_time(totalOffsetTicks, self.bpm)) * 2, totalTicks * 2)] self.tempo = TempoMap(data=data) self.num_bars = len(data) self.scheduler = Scheduler(clock, self.tempo) self.increment_bar = None self.catch_passes = None self.on_commands = [] # commands for a bar of call and response self.off_commands = [] self.active_gems = [] self.gem_commands = [] self.bar_tick = 0 self.bar_index = 0 print(songPattern) def reset(self): #TODO for i in range(len(self.num_bars)): self.clear_bar(i) self.bar_index = 0 def create_bar(self, barIndex): self.bar_tick = quantize_tick_up(self.scheduler.get_tick()) self.active_gems = self.gems[barIndex] # print(list(map(lambda x: x.beat, self.active_gems))) # [gem.activate() for gem in self.active_gems] self._initializeBarAudio(barIndex) self._initializeBarGems(barIndex) # self.increment_bar def clear_bar(self, barIndex): self._clearBarAudio(barIndex) self._clearBarGems() def getRelativeTick(self): tick = quantize_tick_up(self.scheduler.get_tick()) tick = (tick - self.bar_tick) % self.barLenTicks return tick def getTick(self): return quantize_tick_up(self.scheduler.get_tick()) def getTargetGem(self): tick = self.getRelativeTick() beatApprox = (tick / self.barLenTicks) * 4 #find gem by tick targetGem = None minDist = 9999999999 for gem in self.active_gems: if gem.hit or gem.miss: # print("skipping hit gem (target) ", tick) continue gemDist = min(abs(gem.beat - beatApprox), abs(beatApprox - gem.beat)) if gemDist < minDist: minDist = gemDist targetGem = gem # print("minimum dist: ", minDist) # print("targetGem: ", gem.beat) # print("beat approx: ", beatApprox) return targetGem def on_update(self): self.scheduler.on_update() tick = self.getTick() ticksEllapsed = (tick - self.bar_tick) % (self.barLenTicks * 4) if ticksEllapsed <= self.barLenTicks: return "call" elif ticksEllapsed <= self.numRepeats * self.barLenTicks: return "response" else: # print("tick %f, ticksEll %f, barTick %f, barLen %f " % (tick, ticksEllapsed, self.bar_tick, self.barLenTicks)) print('nextStatus') return "next" def bars_remaining(self): tick = self.getTick() ticksEllapsed = (tick - self.bar_tick) % (self.barLenTicks * 4) barNum = round((self.numRepeats * self.barLenTicks - ticksEllapsed) / self.barLenTicks) barsRemaining = np.clip(self.numRepeats - barNum - 1, 0, self.numRepeats - 1) return barsRemaining def _initialize_bars(self, pattern, key): gem_bars = [] chord_bars = [] for bar in pattern: numGems = len(bar) assert numGems > 1 w = (Window.width) // 5 x = self.padding y = self.nowBarHeight chords_and_ticks = [] gems = [] for b in bar: assert b[1] <= self.measuresPerCall * 4 and b[1] > 0 chord = key.generateChord(b[0]) chords_and_ticks.append((chord, b[1])) x = w * b[1] gem = Gem(chord, (x, y), self.gemRadius, self.slack_timout, b[1]) gems.append(gem) chord_bars.append(chords_and_ticks) gem_bars.append(gems) return gem_bars, chord_bars def _initializeBarAudio(self, barIndex): bar_tick = int(self.bar_tick) bar = self.bars[barIndex] # print(self.bar_tick) assert self.numRepeats >= self.playQueues for i in range(self.playQueues): for chord, beat in bar: tick = bar_tick + beat * kTicksPerQuarter # print('audio ', tick) self.on_commands.append( self.scheduler.post_at_tick(self._playChord, tick, chord)) self.off_commands.append( self.scheduler.post_at_tick( self._endChord, tick + kTicksPerQuarter * self.noteDuration, chord)) bar_tick += self.barLenTicks def _clearBarAudio(self, barIndex): for c in self.on_commands: self.scheduler.remove(c) for c in self.off_commands: self.scheduler.remove(c) c.execute() def _initializeBarGems(self, barIndex): slackWinOffset = quantize_tick_up( float(self.slack_timout) / 2 * kTicksPerQuarter) bar_tick = int(self.bar_tick) bar = self.gems[barIndex] for i in range(self.numRepeats): for gem in bar: tick = bar_tick + gem.beat * kTicksPerQuarter if i > 0: self.gem_commands.append( self.scheduler.post_at_tick(self._startGemTimer, tick - slackWinOffset, gem)) ticks_to_time(tick - slackWinOffset, self.bpm) bar_tick += self.barLenTicks self.gem_commands.append( self.scheduler.post_at_tick(self._onCompleteMeasure, bar_tick)) def _refreshBarGems(self): for gem in self.active_gems: gem.on_reset() # gem.activate() def _clearBarGems(self): for gem in self.active_gems: # pass gem.exit() def _onCompleteMeasure(self, tick, temp=None): allHit = True for gem in self.active_gems: allHit = allHit and gem.hit if allHit and not self.on_update() == "call": self.increment_bar(perfect=allHit) print('increment bar') else: print("measure over, resetting gems - %f" % self.getRelativeTick()) self.catch_passes(True) self._refreshBarGems() def _startGemTimer(self, tick, gem): ''' starts the gem timer''' # print("start gem timer %f " % self.getRelativeTick()) if not gem.hit: gem.activate() def _playChord(self, tick, chord): for note in chord._getMidiTones(): self.synth.noteon(self.channel, note, self.vel) def _endChord(self, tick, chord): for note in chord._getMidiTones(): self.synth.noteoff(self.channel, note) def initialize_callbacks(self, increment, catch_passes): self.increment_bar = increment self.catch_passes = catch_passes
class Session(GameObject): def __init__(self, other_members, tempo, bars, divs, inst_set): super(Session, self).__init__() self.tempo = tempo self.bars = bars self.divs = divs self.inst_set = inst_set spb = 60. / tempo beats = bars * 4 self.seconds = spb * beats self.clock = Clock() self.temp_map = SimpleTempoMap(bpm=tempo) self.sched = Scheduler(self.clock, self.temp_map) # self.players = players self.IM = InstrumentManager(self.sched) self.add(self.IM) ### NEW CODE ### self.pattern_list = PatternList(self.bars, self.tempo, self.inst_set) self.add(self.pattern_list) track = Track(num_lanes, self.bars, self.tempo) track.position.y = Window.height * 0.025 controller = InstrumentKeyboard(default_keycodes, lock_in_keycode) self.player = Player(controller, track, inst_set) self.player.position.x = Window.width - player_size[0] - 20 self.add(self.player) self.vplayers = [] self.add_band_members(other_members) self.IM.add(self.player.instrument) self.clock.offset = self.seconds - spb self.paused = True self.start() def add_band_members(self, other_members): for other_member in other_members: vcontroller = InstrumentController(16, other_member['id']) vtrack = VirtualTrack(num_lanes, self.bars, self.tempo) vplayer = VirtualPlayer(vcontroller, vtrack) self.vplayers.append(vplayer) self.add(vplayer) def on_key_down(self, event): # if event.keycode[1] == 'enter':on # self.toggle() pass def toggle(self): if self.paused: self.paused = False self.start() else: self.paused = True self.stop() def stop(self): self.clock.stop() def start(self): self.clock.start() def next_player(self, sequence): if self.current_player < self.num_players: self.players[self.current_player].note_sequence = sequence self.players[self.current_player].stop_composing() self.current_player += 1 if self.current_player < self.num_players: self.players[self.current_player].start_composing() def on_lock_in(self, event): self.next_player(event.action['sequence']) def on_update(self): self.sched.on_update() # for player in self.players: now = self.clock.get_time() % self.seconds for vplayer in self.vplayers: vplayer.set_now(now) self.player.set_now(now) self.pattern_list.set_now(self.clock.get_time() % self.seconds)