def find_hits(self, wf_origin, Init, height_cut, rise_time_cut): wf = np.array(wf_origin) dif = (wf - np.roll(wf, 1)) dif[0] = dif[1] dif_bl = np.median(dif[:Init]) dif_blw = np.sqrt(np.mean((dif[:Init] - dif_bl)**2)) while np.amin(wf) < -height_cut: maxi = np.argmin(wf) if len( np.nonzero( np.logical_and(wf[:maxi] > -self.blw, dif[:maxi] > dif_bl - dif_blw))[0]) > 0: left = np.amax( np.nonzero( np.logical_and(wf[:maxi] > -self.blw, dif[:maxi] > dif_bl - dif_blw))[0]) else: left = 0 if len( np.nonzero( np.logical_and(wf[maxi:] > -self.blw, dif[maxi:] > dif_bl - dif_blw))[0]) > 0: right = maxi + np.amin( np.nonzero( np.logical_and(wf[maxi:] > -self.blw, dif[maxi:] > dif_bl - dif_blw))[0]) else: right = len(wf) if maxi - left > rise_time_cut: hit = Hit(left, right) hit.area = -np.sum(wf[left:right]) self.hits.append(hit) wf[left:right] = 0
def find_hits(self, wf): dif = (wf - np.roll(wf, 1))[1:] dif = np.append(dif[0], dif) dif_bl, dif_blw, j = find_bl_dif(dif) prev_len_out_of_hit = 1e6 out_of_hit = np.arange(len(wf)) counter = 0 while len(out_of_hit)>0 and np.amin(wf[out_of_hit])<-self.blw and np.any(dif[out_of_hit]>dif_bl+dif_blw)\ and len(out_of_hit)<prev_len_out_of_hit: #while len(out_of_hit)>0 and np.amin(wf[out_of_hit])<-self.blw: maxi = out_of_hit[np.argmin(wf[out_of_hit])] left = 0 right = len(wf) - 1 for hit in self.hits: if hit.fin > left and hit.init < maxi: left = hit.fin if hit.init < right and hit.init > maxi: right = hit.init if len(np.nonzero(wf[left:maxi] > -self.blw)[0]) > 0: init_blw = left + np.amax(np.nonzero(wf[left:maxi] > -self.blw)[0]) if len(np.nonzero(dif[left:maxi] > dif_bl - dif_blw)[0]): init_dif = left + np.amax( np.nonzero(dif[left:maxi] > dif_bl - dif_blw)[0]) init = np.amin([init_blw, init_dif]) else: init = left else: init = left if len(np.nonzero(wf[maxi:right] > -self.blw)[0]) > 0: fin_blw = maxi + np.amin(np.nonzero(wf[maxi:right] > -self.blw)[0]) if len(np.nonzero(dif[maxi:right] < dif_bl + dif_blw)[0]): fin_dif = maxi + np.amin( np.nonzero(dif[maxi:right] < dif_bl + dif_blw)[0]) fin = np.amax([fin_blw, fin_dif]) else: fin = right else: fin = right if np.any( dif[init:maxi] < dif_bl - dif_blw ) and wf[maxi] < -min_hit_height and maxi - init > min_hit_rise_time: hit = Hit(init, fin) hit.area = -np.sum(wf[init:fin + 1]) hit.height = -np.amin(wf[init:fin + 1]) find_groups(hit, wf, dif, self.blw) self.hits.append(hit) prev_len_out_of_hit = len(out_of_hit) for i in np.arange(init, fin + 1): out_of_hit = np.delete(out_of_hit, np.nonzero(out_of_hit == i)[0]) counter += 1 self.hits = sorted(self.hits, key=lambda hit: hit.init) merge_hits(self, wf, self.blw) for hit in self.hits: hit.groups = sorted(hit.groups, key=lambda grp: grp.maxi)
def main(): def _dump_data(): try: obj = dict( params=dict( allowed_rhythm_deviation=allowed_rhythm_deviation, allowed_tempo_deviation=allowed_tempo_deviation, current_level=current_level, experiment_type=experiment_type, trial_on_path=trial_on_path, truth_on_path=truth_on_path, ), processing=dict( hits=[h.to_dict() for h in hits], messages=[m.to_dict() for m in msgs], messages_tempo_transformed=[ tmsg.to_dict() for tmsg in tempoed_msgs ], tempo_estimation=tempo_estimation, tempo_str=tempo_str, ), results=dict( passed=passed, mistakes=mistakes, played_enough_notes=played_enough_notes, ), ) if check_rhythm: obj['processing'].update( tempo_ceil=tempo_ceil, tempo_floor=tempo_floor, ) if not passed: # only time when passed is True (all_hits_correct), advance_trial isn't referenced obj['results'].update(advance_trial=advance_trial) with open(data_dump_path, mode='w') as f: json.dump(obj, f, indent=4, sort_keys=True) except: pass if len(sys.argv) > 1: allowed_rhythm_deviation = int(sys.argv[1][:-1]) allowed_tempo_deviation = int(sys.argv[2][:-1]) trial_on_path = sys.argv[3] truth_on_path = sys.argv[4] current_level = json.loads(sys.argv[5]) experiment_type = sys.argv[6] else: allowed_rhythm_deviation = 20 allowed_tempo_deviation = 30 trial_on_path = r'c:\Sync\Code\Python\Pyano-release\src\experiments\subjects\tests\ORIN\level_1_trial_0_on.txt' truth_on_path = r'c:\Sync\Code\Python\Pyano-release\src\experiments\truths\fur_elise_B_on.txt' current_level = dict(notes=10, trials=1, rhythm=True, tempo=50) experiment_type = 'exam' data_dump_path = trial_on_path.rpartition('_on.txt')[0] + '_data.json' truths: List[Message] = Message.normalize_chords_in_file(truth_on_path) msgs: List[Message] = Message.normalize_chords_in_file(trial_on_path) check_rhythm = current_level['rhythm'] current_level_notes = current_level['notes'] tempo_estimation = estimate_tempo_percentage(msgs, truths, current_level_notes) tempoed_msgs: List[Message] = Message.transform_to_tempo( msgs, tempo_estimation) mistakes = [] hits = [] # for data dumping truth_chords = Message.get_chords(truths[:current_level_notes]) try: Message.normalize_chords( tempoed_msgs, truth_chords) # of tempoed_msgs, according to truth_chords except Exception as e: entry = logger.log( dict(tempoed_msgs=tempoed_msgs, truth_chords=truth_chords, msg=msgs, current_level_notes=current_level_notes, check_rhythm=check_rhythm, tempo_estimation=tempo_estimation, truths=truths, e=e), title= f"Exception at Message.normalize_chords(tempoed_msgs, truth_chords)" ) raise Exception( f"check done trial normalize chords exception. see log check_done_trial, entry: {entry}" ) for i in range(min(current_level_notes, len(msgs))): hit = Hit(tempoed_msgs[i], truths[i], allowed_rhythm_deviation) hits.append(hit) mistakes.append(hit.get_mistake_kind()) played_enough_notes = len(msgs) >= current_level_notes if not played_enough_notes: # needed to play 4 notes but playeed 3: [ null, null, null, "accuracy" ] # if also made a mistake: [ null, "rhythm", null, "accuracy" ] # Failed feedback msg could be "[ null, 'rhythm', null, 'accuracy' ], not enough notes and too fast" mistakes += ["accuracy"] * (current_level_notes - len(msgs)) tempo_str = "ok" if check_rhythm: # Failed feedback msg could be "[ null, 'rhythm', null, 'accuracy' ] and too fast" if not (0 <= allowed_tempo_deviation <= 100): entry = logger.log( dict(trial_on_path=trial_on_path, truth_on_path=truth_on_path, current_level=current_level, allowed_tempo_deviation=allowed_tempo_deviation), title="check_done_trial ValueError bad allowed_tempo_deviation" ) raise ValueError( f"check_done_trial inside rhythm checking got bad allowed_tempo_deviation, got: {allowed_tempo_deviation}. see classes.log, entry: {entry}" ) level_tempo = current_level['tempo'] # 75 extra = level_tempo * allowed_tempo_deviation / 100 # 75*0.1 = 7.5 tempo_floor = level_tempo - extra # 67.5 tempo_ceil = max(100, level_tempo + extra) # max(100, 82.5) = 100 if tempo_estimation < tempo_floor: tempo_str = "slow" elif tempo_estimation > tempo_ceil: tempo_str = "fast" else: tempo_str = "ok" if tempo_str != 'ok': # acc mistake when checking rhythm. if experiemnt is exam, advance anyway if experiment_type == 'exam': advance_trial = True else: advance_trial = 'accuracy' not in mistakes passed = False _dump_data() prfl( dict( advance_trial=advance_trial, mistakes=mistakes, passed=passed, played_enough_notes=played_enough_notes, tempo_str=tempo_str, )) return else: # delete rhythm mistakes if not checking rhythm. ["rhythm", null, "accuracy"] => [null, null, "accuracy"] mistakes = [None if m == "rhythm" else m for m in mistakes] if not played_enough_notes: # not enough notes == accuracy mistakes. dont adv if check rhythm. if experiemnt is exam, advance anyway if experiment_type == 'exam': advance_trial = True else: advance_trial = not check_rhythm passed = False played_enough_notes = False _dump_data() prfl( dict(passed=passed, mistakes=mistakes, advance_trial=advance_trial, played_enough_notes=played_enough_notes, tempo_str=tempo_str)) return # Played all notes or too many notes all_hits_correct = all([mistake is None for mistake in mistakes]) if all_hits_correct: passed = True played_too_many_notes = len(msgs) > current_level_notes _dump_data() prfl(dict(passed=passed, played_too_many_notes=played_too_many_notes)) return else: # Had mistakes # Tempo ok, played all required notes # if not check rhythm: has accuracy mistakes # if check rhythm: has accuracy and/or rhythm mistakes # ['accuracy', 'rhythm', None, ...] if experiment_type == 'exam': advance_trial = True else: advance_trial = not (check_rhythm and 'accuracy' in mistakes) passed = False _dump_data() prfl( dict(passed=passed, advance_trial=advance_trial, mistakes=mistakes))