def __init__(self, surf, **kwds): RootWidget.__init__(self, surf, **kwds) self.bg_color = (255,255,255) self.redraw_every_frame = True self.set_timer(50) self.recording_in_progress = False # signal buffer stores 6 seconds of data self.sig_buf = SignalBuffer(768, 14) # add status update callbacks to the device monitor mon.callbacks.append(self.update_device_status) mon.callbacks.append(self.start_device_reader) self.gyrox_label = Label('', width = 80, height = 30, bg_color = (30, 30, 255)) self.gyroy_label = Label('', width = 80, height = 30, bg_color = (30, 30, 255)) self.signal_mag_label = Label('', width = 80, height = 30) small_font = pygame.font.SysFont('Ubuntu', 12) self.renderer = SignalRendererWidget(counter_to_sensor_id, dev, self.sig_buf, Rect(0, 0, 880, 660)) self.add(self.renderer) c = Column([ Button("Start REC", action = self.start_recording, enabled = lambda: not self.recording_in_progress, bg_color = (0, 0, 128), height = 30, margin = 3), Button("Stop REC", action = self.stop_recording, enabled = lambda: self.recording_in_progress, bg_color = (0, 0, 128), height = 30, margin = 3), Widget(height = 70), Label('Gyro Data', height = 30), self.gyrox_label, self.gyroy_label, Button("Cursor", action = self.toggle_cursor_rendering, bg_color = (255, 0, 0), height = 30, margin = 3), # Widget(height = 30), Label('EEG Mag', height = 30), Row( [ Button("+", action = lambda: self.renderer.update_magnification(+0.2), bg_color = (80, 100, 40), width = 30, margin = 5), Button("-", action = lambda: self.renderer.update_magnification(-0.2), bg_color = (80, 100, 40), margin = 5, width = 30) ]), self.signal_mag_label, Button("Clear", action = lambda: self.sig_buf.clear(), bg_color = (255, 0, 0), height = 30, margin = 5), Label('Channels', width = 100, bg_color = (50, 50, 255)), Grid([ [ Button("F3", font = small_font, action = lambda: self.renderer.toggle_channel(0)), Button("FC5", font = small_font, action = lambda: self.renderer.toggle_channel(1)), Button("AF3", font = small_font, action = lambda: self.renderer.toggle_channel(2)), Button("F7", font = small_font, action = lambda: self.renderer.toggle_channel(3)) ], [ Button("T7", font = small_font, action = lambda: self.renderer.toggle_channel(4)), Button("P7", font = small_font, action = lambda: self.renderer.toggle_channel(5)), Button("O1", font = small_font, action = lambda: self.renderer.toggle_channel(6)), Button("O2", font = small_font, action = lambda: self.renderer.toggle_channel(7)) ], [ Button("P8", font = small_font, action = lambda: self.renderer.toggle_channel(8)), Button("T8", font = small_font, action = lambda: self.renderer.toggle_channel(9)), Button("F8", font = small_font, action = lambda: self.renderer.toggle_channel(10)), Button("AF4", font = small_font, action = lambda: self.renderer.toggle_channel(11)) ], [ Button("FC6", font = small_font, action = lambda: self.renderer.toggle_channel(12)), Button("F4", font = small_font, action = lambda: self.renderer.toggle_channel(13)) ] ], row_spacing = 5, column_spacing = 8, width = 100), # Widget(height = 55), Button(" QUIT ", action = self.quit, bg_color = (200, 0, 64), margin = 5 )], align = 'c', spacing = 20, bg_color = (50, 50, 50), rect = Rect(880, 0, 120, 690), height = 690, expand = True, margin = 5) self.stat_label = Label('', 100, margin = 3) self.packet_speed_label = Label('', 100, margin = 3) self.recording_label = Label('NOT RECORDING', 400, margin = 3) self.battery_label = Label('NO DATA', 100, margin = 3) r = Row([ self.stat_label, self.packet_speed_label, self.battery_label, self.recording_label, Widget(width = 50, height = 30) ], rect = Rect(0, 660, 880, 30), width = 880, height = 30, expand = True, margin = 5, spacing = 20, bg_color = (50, 50, 50)) self.add(c) self.add(r) # first update is manual self.update_device_status(mon.check_connected()) # eeg rendering widget self.renderer = SignalRendererWidget(counter_to_sensor_id, dev, self.sig_buf, Rect(0, 0, 880, 660)) self.add(self.renderer) self.update_ps_counter = 0 self.rec = None self.render_cursor = False self.sq_pos = (400, 300)
class WaveRiderGUI(RootWidget): """ The GUI elements of the main screen for wave rider. """ def __init__(self, surf, **kwds): RootWidget.__init__(self, surf, **kwds) self.bg_color = (255,255,255) self.redraw_every_frame = True self.set_timer(50) self.recording_in_progress = False # signal buffer stores 6 seconds of data self.sig_buf = SignalBuffer(768, 14) # add status update callbacks to the device monitor mon.callbacks.append(self.update_device_status) mon.callbacks.append(self.start_device_reader) self.gyrox_label = Label('', width = 80, height = 30, bg_color = (30, 30, 255)) self.gyroy_label = Label('', width = 80, height = 30, bg_color = (30, 30, 255)) self.signal_mag_label = Label('', width = 80, height = 30) small_font = pygame.font.SysFont('Ubuntu', 12) self.renderer = SignalRendererWidget(counter_to_sensor_id, dev, self.sig_buf, Rect(0, 0, 880, 660)) self.add(self.renderer) c = Column([ Button("Start REC", action = self.start_recording, enabled = lambda: not self.recording_in_progress, bg_color = (0, 0, 128), height = 30, margin = 3), Button("Stop REC", action = self.stop_recording, enabled = lambda: self.recording_in_progress, bg_color = (0, 0, 128), height = 30, margin = 3), Widget(height = 70), Label('Gyro Data', height = 30), self.gyrox_label, self.gyroy_label, Button("Cursor", action = self.toggle_cursor_rendering, bg_color = (255, 0, 0), height = 30, margin = 3), # Widget(height = 30), Label('EEG Mag', height = 30), Row( [ Button("+", action = lambda: self.renderer.update_magnification(+0.2), bg_color = (80, 100, 40), width = 30, margin = 5), Button("-", action = lambda: self.renderer.update_magnification(-0.2), bg_color = (80, 100, 40), margin = 5, width = 30) ]), self.signal_mag_label, Button("Clear", action = lambda: self.sig_buf.clear(), bg_color = (255, 0, 0), height = 30, margin = 5), Label('Channels', width = 100, bg_color = (50, 50, 255)), Grid([ [ Button("F3", font = small_font, action = lambda: self.renderer.toggle_channel(0)), Button("FC5", font = small_font, action = lambda: self.renderer.toggle_channel(1)), Button("AF3", font = small_font, action = lambda: self.renderer.toggle_channel(2)), Button("F7", font = small_font, action = lambda: self.renderer.toggle_channel(3)) ], [ Button("T7", font = small_font, action = lambda: self.renderer.toggle_channel(4)), Button("P7", font = small_font, action = lambda: self.renderer.toggle_channel(5)), Button("O1", font = small_font, action = lambda: self.renderer.toggle_channel(6)), Button("O2", font = small_font, action = lambda: self.renderer.toggle_channel(7)) ], [ Button("P8", font = small_font, action = lambda: self.renderer.toggle_channel(8)), Button("T8", font = small_font, action = lambda: self.renderer.toggle_channel(9)), Button("F8", font = small_font, action = lambda: self.renderer.toggle_channel(10)), Button("AF4", font = small_font, action = lambda: self.renderer.toggle_channel(11)) ], [ Button("FC6", font = small_font, action = lambda: self.renderer.toggle_channel(12)), Button("F4", font = small_font, action = lambda: self.renderer.toggle_channel(13)) ] ], row_spacing = 5, column_spacing = 8, width = 100), # Widget(height = 55), Button(" QUIT ", action = self.quit, bg_color = (200, 0, 64), margin = 5 )], align = 'c', spacing = 20, bg_color = (50, 50, 50), rect = Rect(880, 0, 120, 690), height = 690, expand = True, margin = 5) self.stat_label = Label('', 100, margin = 3) self.packet_speed_label = Label('', 100, margin = 3) self.recording_label = Label('NOT RECORDING', 400, margin = 3) self.battery_label = Label('NO DATA', 100, margin = 3) r = Row([ self.stat_label, self.packet_speed_label, self.battery_label, self.recording_label, Widget(width = 50, height = 30) ], rect = Rect(0, 660, 880, 30), width = 880, height = 30, expand = True, margin = 5, spacing = 20, bg_color = (50, 50, 50)) self.add(c) self.add(r) # first update is manual self.update_device_status(mon.check_connected()) # eeg rendering widget self.renderer = SignalRendererWidget(counter_to_sensor_id, dev, self.sig_buf, Rect(0, 0, 880, 660)) self.add(self.renderer) self.update_ps_counter = 0 self.rec = None self.render_cursor = False self.sq_pos = (400, 300) def start_device_reader(self, status): if status: dev.start_reader() def update_device_status(self, status): self.stat_label.text = 'ONLINE' if status else 'OFFLINE' self.stat_label.bg_color = (50, 255, 50) if status else (255, 30, 30) self.stat_label.invalidate() def update_packet_speed_label(self): if self.update_ps_counter > 10: self.packet_speed_label.text = '%.1f S/sec' % dev.packet_speed if dev.packet_speed > 0 else 'NO DATA' self.packet_speed_label.bg_color = (50, 255, 50) if dev.packet_speed > 0 else (255, 30, 30) self.packet_speed_label.invalidate() self.update_ps_counter = 0 else: self.update_ps_counter += 1 def update_gyro_labels(self): if dev.gyro_x is not None: self.gyrox_label.text = 'X = %d' % dev.gyro_x if dev.gyro_y is not None: self.gyroy_label.text = 'Y = %d' % dev.gyro_y def toggle_cursor_rendering(self): if self.render_cursor == False: self.sq_pos = (400, 300) self.render_cursor = not self.render_cursor def begin_frame(self): self.update_packet_speed_label() self.update_gyro_labels() self.signal_mag_label.text = 'mag: %gx' % self.renderer.multiplier self.signal_mag_label.invalidate() if dev.battery is not None: self.battery_label.text = 'BATT: %d%%' % (dev.battery * 100) else: self.battery_label.text = 'NO DATA' self.battery_label.invalidate() # no sense in updating if we are not going to use it if self.render_cursor and (dev.gyro_x is not None) and (dev.gyro_y is not None): new_pos_x = max(20, min(800, self.sq_pos[0] + (105 - dev.gyro_x) * 4)) if abs(dev.gyro_x - 105) > 1 else self.sq_pos[0] new_pos_y = max(20, min(600, self.sq_pos[1] + (dev.gyro_y - 105) * 4)) if abs(dev.gyro_y - 105) > 1 else self.sq_pos[1] self.sq_pos = new_pos_x, new_pos_y RootWidget.begin_frame(self) def draw_all(self, surf): # draw the root widgets Widget.draw_all(self, surf) # only render the cursor if required if self.render_cursor: pos = self.sq_pos pygame.draw.rect(display, (0, 0, 0), Rect(pos[0] - 10, pos[1] - 10, 20, 20)) def start_recording(self): if self.rec is not None: albow.dialogs.alert('Recording in progress!') return fname = albow.file_dialogs.request_new_filename("Select output file ...", suffix = "csv", directory = 'data') if fname is None: return # start the recording self.rec = SignalWriter() self.rec.open(fname) if not self.rec.ready(): albow.dialogs.alert("File cannot be opened, cancelling recording.") self.rec = None return # update the recording label self.recording_label.text = 'Recording to [%s]' % os.path.basename(fname) self.recording_label.bg_color = (255, 30, 30) self.recording_label.invalidate() dev.subscribe(self.rec.write_packet) def stop_recording(self): if self.rec is None: albow.dialogs.alert("There is no recording in progress.") return # stop the recording dev.unsubscribe(self.rec.write_packet) self.rec.close() self.rec = None # update the recording label self.recording_label.text = 'NOT RECORDING' self.recording_label.bg_color = (50, 50, 50) self.recording_label.invalidate() def confirm_quit(self): """ Check if we really want to quit. """ if self.rec is not None: albow.dialogs.alert("You are recording! Stop the recording before exiting.") return return albow.dialogs.ask("Are you sure you want to quit?", ["Yes", "No"]) == "Yes" def exit_cmd(self): self.quit() def quit(self): if not self.confirm_quit(): return # we're quitting mon.stop() dev.stop_reader() pygame.quit() sys.exit(0)
from emotiv_device import EmotivDevice from emotiv_data_packet import EmotivDataPacket from signal_buffer import SignalBuffer if __name__ == '__main__': print("Setting up device ...") dev = EmotivDevice('SN20120229000254') print("Starting reader ...") dev.start_reader() rb = SignalBuffer(64, 14) for rbp in range(10): pp = rb.pull_packets(dev) print("Pulled %d packets." % pp) print rb.buffer().shape time.sleep(0.2) print("Stopping reader ...") dev.stop_reader() print("Done.")
if __name__ == '__main__': # signal writer for storing samples sw = SignalWriter() sw.open('signal.csv') print("Signal writer is ready: %s" % sw.ready()) # initialize the devices & buffer dev = EmotivDevice('SN20120229000254') dev.subscribe(sw.write_packet) dev.start_reader() # signal buffer for reading samples from the EEG eeg = SignalBuffer(750, 14) # PyGame subsystem init pygame.init() Clock = pygame.time.Clock() try: screen = pygame.display.set_mode((800, 600)) myFont = pygame.font.SysFont("Ubuntu", 20, True) chan_names = [] for s in range(len(counter_to_sensor_id)): chan_names.append(myFont.render(counter_to_sensor_id[s], 1, (0, 0, 0))) while mainloop:
def main(): parser = argparse.ArgumentParser(description="Stream audio data from pipe") parser.add_argument("--inputs", "-i", type=int) parser.add_argument("--outputs", "-o", action="append", type=int) parser.add_argument( "--framelength", "-fl", type=float, default=25., help="Frame length in milliseconds (default: {})".format(25.)) parser.add_argument( "--frameshift", "-fs", type=float, default=10., help="Frame shift in milliseconds (default: {})".format(10.)) parser.add_argument( "--samplingfrequency", "-sf", type=int, default=16000, help="Sampling frequency (rate) (default: {})".format(16000)) parser.add_argument("--numberofchannels", "-noc", type=int, default=8, help="Number of channels (default: {})".format(8)) parser.add_argument("--validchannels", "-vc", type=str, default="0,1,2,3,4,5", help="Comma-separated list of valid channel indices " "(default: \"{}\")".format("0,1,2,3,4,5")) parser.add_argument("--notinterleaved", action="store_true", help="Input is *not* interleaved") parser.add_argument("--inputfilepath", "-ifp", type=str, help="Path to file which the valid input is written " "to") parser.add_argument( "--soundcard", "-sc", type=str, help="(Prefix of) Soundcard name (default: \"{}\"".format( "audioinjector"), default="audioinjector") # TODO #parser.add_argument("--format", "-f", choices=["UInt8", "Int8", "Int16", # "Int24", "Int32", "Float32"], # default="Int32") parser.add_argument("--format", "-f", choices=["UInt8", "Int8", "Int16", "Int32", "Float32"], default="Int32", help="Format of the input data " "(default: {})".format("Int32")) args = parser.parse_args() input_pipes = [] if args.inputs is not None: input_pipes = [os.fdopen(fd, 'rb') for fd in args.inputs] output_pipes = [] if args.outputs is not None: output_pipes = [os.fdopen(fd, 'wb') for fd in args.outputs] outputs = [ pickle.Pickler(pipe, pickle.HIGHEST_PROTOCOL) for pipe in output_pipes ] f = Format(args.format) valid_channels = np.array( [int(chan) for chan in args.validchannels.split(",")]) frame_length = int((args.framelength * args.samplingfrequency) / 1000.0) frameshift = int((args.frameshift * args.samplingfrequency) / 1000.0) signal_buffer = SignalBuffer(frame_length, len(valid_channels)) if len(input_pipes) == 0: pa = pyaudio.PyAudio() audioinjector_idx = None for idx in range(pa.get_device_count()): info = pa.get_device_info_by_index(idx) if info["name"].lower().startswith(args.soundcard.lower()): audioinjector_idx = info["index"] if audioinjector_idx is None: raise ValueError("Given soundcard name \"{}\" not found".format( args.soundcard)) stream = pa.open(format=f.pyaudioformat, channels=args.numberofchannels, rate=args.samplingfrequency, input=True, frames_per_buffer=frameshift) if args.inputfilepath is not None: wavfile = wave.open(args.inputfilepath, "wb") wavfile.setnchannels(len(valid_channels)) wavfile.setsampwidth(f.size) wavfile.setframerate(args.samplingfrequency) while True: if len(input_pipes) == 0: in_data = np.fromstring(stream.read(frameshift, exception_on_overflow=False), dtype=f.type) else: # XXX: !!! no endianness defined !!! in_data = np.fromfile(inp, dtype=f.type, count=args.numberofchannels * frameshift) if args.notinterleaved: innovation = in_data.reshape((args.numberofchannels, frameshift)).T else: innovation = in_data.reshape((frameshift, args.numberofchannels)) innovation = f.converttofloat(innovation[:, valid_channels]) innovation = innovation.flatten('F') frame = signal_buffer.process(innovation) if args.inputfilepath is not None: wavfile.writeframes(f.convertfromfloat(innovation).tobytes()) for out in output_pipes: out.write(frame.tobytes()) out.flush() #for out_idx in range(len(outputs)): # outputs[out_idx].dump(frame) # outputs[out_idx].clear_memo() # output_pipes[out_idx].flush() if args.inputfilepath is not None: wavfile.close() if len(input_pipes) == 0: stream.stop_stream() stream.close() pa.terminate() for pipe in input_pipes: pipe.close() for pipe in output_pipes: pipe.close()