diff options
-rw-r--r-- | audiograb.py | 147 | ||||
-rw-r--r-- | drawwaveform.py | 30 | ||||
-rw-r--r-- | measure.py | 6 |
3 files changed, 116 insertions, 67 deletions
diff --git a/audiograb.py b/audiograb.py index 610a903..ef91631 100644 --- a/audiograb.py +++ b/audiograb.py @@ -24,6 +24,7 @@ import gst.interfaces from numpy import fromstring import os import subprocess +import traceback from string import find from threading import Timer @@ -45,7 +46,7 @@ SENSOR_DC_NO_BIAS = 'voltage' SENSOR_DC_BIAS = 'resistance' -class AudioGrab: +class AudioGrab(): """ The interface between measure and the audio device """ def __init__(self, callable1, activity): @@ -63,7 +64,7 @@ class AudioGrab: self.screenshot = True self.rate = RATE - self._channels = self.activity.wave.channels + self._channels = None self.final_count = 0 self.count_temp = 0 self.entry_count = 0 @@ -81,9 +82,16 @@ class AudioGrab: self._hardwired = False # Query controls or use hardwired names self._display_value = DISPLAY_DUTY_CYCLE - # Set up gstreamer pipeline + self._query_mixer() + if self._channels is None: # didn't find channels in any controllers + self._channels = 2 + self.activity.wave.set_channels(self._channels) + # Set up gstreamer pipeline self._pad_count = 0 + self.pads = [] + self.queue = [] + self.fakesink = [] self.pipeline = gst.Pipeline('pipeline') self.alsasrc = gst.element_factory_make('alsasrc', 'alsa-source') self.pipeline.add(self.alsasrc) @@ -92,34 +100,42 @@ class AudioGrab: caps_str = 'audio/x-raw-int,rate=%d,channels=%d,depth=16' % ( RATE, self._channels) self.caps1.set_property('caps', gst.caps_from_string(caps_str)) - self.queue = [None, None] - self.fakesink = [None, None] if self._channels == 1: - self.fakesink[0] = gst.element_factory_make('fakesink', 'fsink') + self.fakesink.append(gst.element_factory_make('fakesink', 'fsink')) self.pipeline.add(self.fakesink[0]) self.fakesink[0].connect('handoff', self.on_buffer) self.fakesink[0].set_property('signal-handoffs', True) gst.element_link_many(self.alsasrc, self.caps1, self.fakesink[0]) - else: # We only process 2 channels - self.splitter = gst.element_factory_make('deinterleave', - 'splitter') - self.pipeline.add(self.splitter) - self.splitter.set_properties('keep-positions=true', 'name=d') - self.splitter.connect('pad-added', self._splitter_pad_added) + else: + if not hasattr(self, 'splitter'): + self.splitter = gst.element_factory_make('deinterleave') + self.pipeline.add(self.splitter) + self.splitter.set_properties('keep-positions=true', 'name=d') + self.splitter.connect('pad-added', self._splitter_pad_added) + gst.element_link_many(self.alsasrc, self.caps1, self.splitter) for i in range(self._channels): - self.queue[i] = gst.element_factory_make('queue', - 'queue%d' % (i)) + self.queue.append(gst.element_factory_make('queue')) self.pipeline.add(self.queue[i]) - self.fakesink[i] = gst.element_factory_make('fakesink', - 'fsink%d' % (i)) + self.fakesink.append(gst.element_factory_make('fakesink')) self.pipeline.add(self.fakesink[i]) self.fakesink[i].connect('handoff', self.on_buffer, i) self.fakesink[i].set_property('signal-handoffs', True) - gst.element_link_many(self.alsasrc, self.caps1, self.splitter) - self.dont_queue_the_buffer = False + # Variables for saving and resuming state of sound device + self.master = self.get_master() + self.bias = BIAS + self.dcmode = DC_MODE_ENABLE + self.capture_gain = CAPTURE_GAIN + self.mic_boost = MIC_BOOST + self.mic = self.get_mic_gain() + + # Timer for interval sampling and switch to indicate when to capture + self.capture_timer = None + self.capture_interval_sample = False + + def _query_mixer(self): self._mixer = gst.element_factory_make('alsamixer') rc = self._mixer.set_state(gst.STATE_PAUSED) assert rc == gst.STATE_CHANGE_SUCCESS @@ -128,6 +144,16 @@ class AudioGrab: try: # F11+ log.debug('controls: %r', [t.props.untranslated_label \ for t in self._mixer.list_tracks()]) + self._capture_control = self._find_control(['capture']) + if self._capture_control is not None: + log.debug('Capture is %s' % ( + self._capture_control.props.untranslated_label)) + log.debug('Min %s' % (str(self._capture_control.min_volume))) + log.debug('Max %s' % (str(self._capture_control.max_volume))) + log.debug('Channels %s' % ( + str(self._capture_control.num_channels))) + if self._channels is None: + self._channels = self._capture_control.num_channels self._dc_control = self._find_control(['dc mode']) self._mic_bias_control = self._find_control(['mic bias', 'dc input bias', @@ -139,6 +165,8 @@ class AudioGrab: log.debug('Max %s' % (str(self._mic_bias_control.max_volume))) log.debug('Channels %s' % ( str(self._mic_bias_control.num_channels))) + if self._channels is None: + self._channels = self._mic_bias_control.num_channels self._mic_boost_control = self._find_control(['mic boost', 'mic boost (+20db)', 'internal mic boost', @@ -150,49 +178,49 @@ class AudioGrab: log.debug('Max %s' % (str(self._mic_boost_control.max_volume))) log.debug('Channels %s' % ( str(self._mic_boost_control.num_channels))) + if self._channels is None: + self._channels = self._mic_boost_control.num_channels self._mic_gain_control = self._find_control(['mic']) - self._capture_control = self._find_control(['capture']) - if self._capture_control is not None: - log.debug('Capture is %s' % ( - self._capture_control.props.untranslated_label)) - log.debug('Min %s' % (str(self._capture_control.min_volume))) - log.debug('Max %s' % (str(self._capture_control.max_volume))) - log.debug('Channels %s' % ( - str(self._capture_control.num_channels))) self._master_control = self._find_control(['master']) except AttributeError: # F9- (no untranslated_label attribute) self._hardwired = True - # Variables for saving and resuming state of sound device - self.master = self.get_master() - self.bias = BIAS - self.dcmode = DC_MODE_ENABLE - self.capture_gain = CAPTURE_GAIN - self.mic_boost = MIC_BOOST - self.mic = self.get_mic_gain() + def _unlink_sink_queues(self): + ''' Build the sink pipelines ''' - # Timer for interval sampling and switch to indicate when to capture - self.capture_timer = None - self.capture_interval_sample = False + # If there were existing pipelines, unlink them + for i in range(self._pad_count): + log.debug('unlinking old elements') + try: + self.splitter.unlink(self.queue[i]) + self.queue[i].unlink(self.fakesink[i]) + except: + traceback.print_exc() + + # Build the new pipelines + self._pad_count = 0 + self.pads = [] + log.debug('building new pipelines') def _splitter_pad_added(self, element, pad): ''' Seems to be the case that ring is right channel 0, tip is left channel 1''' log.debug('splitter pad %d added' % (self._pad_count)) - if (self._pad_count < MAX_GRAPHS): + self.pads.append(pad) + if (self._pad_count < min(self._channels, MAX_GRAPHS)): pad.link(self.queue[self._pad_count].get_pad('sink')) self.queue[self._pad_count].get_pad('src').link( self.fakesink[self._pad_count].get_pad('sink')) self._pad_count += 1 else: - log.debug('ignoring channels > %d' % (MAX_GRAPHS)) + log.debug('ignoring channels > %d' % (min(self._channels, + MAX_GRAPHS))) def set_handoff_signal(self, handoff_state): '''Sets whether the handoff signal would generate an interrupt or not''' - self.fakesink[0].set_property('signal-handoffs', handoff_state) - if self._channels == 2: - self.fakesink[1].set_property('signal-handoffs', handoff_state) + for i in range(len(self.fakesink)): + self.fakesink[i].set_property('signal-handoffs', handoff_state) def _new_buffer(self, buf, channel): ''' Use a new buffer ''' @@ -205,14 +233,12 @@ class AudioGrab: def on_buffer(self, element, buffer, pad, channel): '''The function that is called whenever new data is available This is the signal handler for the handoff signal''' + # log.debug('on_buffer: channel %d' % (channel)) temp_buffer = fromstring(buffer, 'int16') if not self.dont_queue_the_buffer: + # log.debug('on_buffer: calling _new_buffer') self._new_buffer(temp_buffer, channel=channel) - # FIXME: manage multiple channels - if channel > 0: - return False - if self.logging_state: # If we've hit the maximum no. of log files, stop. if self.waveform_id == SOUND_MAX_WAVE_LOGS: @@ -232,11 +258,13 @@ class AudioGrab: # In sensor mode, periodly update the textbox with a sample value if self.activity.CONTEXT == 'sensor' and not self.logging_state: + # log.debug('on_buffer: setting display value') if self._display_value == 0: # Display value at DISPLAY_DUTY_CYCLE self.sensor.set_sample_value(str(temp_buffer[0])) self._display_value = DISPLAY_DUTY_CYCLE else: self._display_value -= 1 + # log.debug('on_buffer: return False') return False def set_freeze_the_display(self, freeze=False): @@ -343,6 +371,7 @@ class AudioGrab: def start_grabbing(self): '''Called right at the start of the Activity''' self.start_sound_device() + self.set_handoff_signal(True) def pause_grabbing(self): '''When Activity goes into background''' @@ -353,6 +382,7 @@ class AudioGrab: '''When Activity becomes active after going to background''' self.start_sound_device() self.resume_state() + self.set_handoff_signal(True) def stop_grabbing(self): '''Not used ???''' @@ -777,17 +807,31 @@ class AudioGrab: } mode, bias, gain, boost = PARAMETERS[sensor_type] log.debug('====================================') - log.debug('Set Sensor Type to %s' % (str(sensor_type))) + log.debug('Set sensor type to %s' % (str(sensor_type))) self._set_sensor_type(mode, bias, gain, boost) log.debug('====================================') def _set_sensor_type(self, mode=None, bias=None, gain=None, boost=None): '''Helper to modify (some) of the sensor settings.''' - if mode is not None: - self.set_dc_mode(mode) - if self._dc_control is not None: - os.system('amixer get "%s"' %\ - (self._dc_control.props.untranslated_label)) + + log.debug('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>') + log.debug('parameters: %s %s %s %s' % (str(mode), str(bias), + str(gain), str(boost))) + log.debug('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>') + log.debug('%s %s' % (str(mode), str(self.dcmode))) + if mode is not None and mode != self.dcmode: + # If we change to/from dcmode, we need to rebuild the pipelines + self.stop_grabbing() + self._unlink_sink_queues() + + if mode is not None: + self.set_dc_mode(mode) + if self._dc_control is not None: + os.system('amixer get "%s"' %\ + (self._dc_control.props.untranslated_label)) + self.dcmode = mode + self.start_grabbing() + if bias is not None: self.set_bias(bias) if self._mic_bias_control is not None: @@ -823,7 +867,6 @@ class AudioGrab_XO1(AudioGrab): ''' Use default parameters for OLPC XO 1.0 laptop ''' pass - class AudioGrab_XO15(AudioGrab): ''' Override parameters for OLPC XO 1.5 laptop ''' def set_sensor_type(self, sensor_type=SENSOR_AC_BIAS): diff --git a/drawwaveform.py b/drawwaveform.py index c153ea4..5d64e16 100644 --- a/drawwaveform.py +++ b/drawwaveform.py @@ -117,6 +117,17 @@ class DrawWaveform(gtk.DrawingArea): self.source = [] self.graph_id = [] + self.max_samples = 115 + self.max_samples_fact = 3 + + self.time_div = 1.0 + self.freq_div = 1.0 + self.input_step = 1 + + self.debug_str = 'start' + + self.context = True + for x in range(0, self.MAX_GRAPHS): self.graph_show_state.append(False) self.Xstart.append(0) @@ -128,6 +139,11 @@ class DrawWaveform(gtk.DrawingArea): self.source.append(0) self.graph_id.append(x) + self.ringbuffer = [] + + def set_channels(self, channels): + ''' Add buffer per channel ''' + self.channels = channels for i in range(min(self.channels, self.MAX_GRAPHS)): self.graph_show_state[i] = True self.Xstart[i] = 0 @@ -143,19 +159,9 @@ class DrawWaveform(gtk.DrawingArea): self.color[i] = '#FFFFFF' self.source[i] = 0 - self.max_samples = 115 - self.max_samples_fact = 3 - - self.time_div = 1.0 - self.freq_div = 1.0 - self.input_step = 1 - - self.ringbuffer = [None, None] for i in range(self.channels): - self.ringbuffer[i] = RingBuffer1d(self.max_samples, dtype='int16') - self.debug_str = 'start' - - self.context = True + self.ringbuffer.append(RingBuffer1d(self.max_samples, + dtype='int16')) def set_max_samples(self, num): """ Maximum no. of samples in ringbuffer """ @@ -154,16 +154,16 @@ class MeasureActivity(activity.Activity): self.hw = _get_hardware() log.debug('running on %s hardware' % (self.hw)) if self.hw == XO15: - self.wave = DrawWaveform(self, channels=2) + self.wave = DrawWaveform(self) self.audiograb = AudioGrab_XO15(self.wave.new_buffer, self) elif self.hw == XO175: - self.wave = DrawWaveform(self, channels=2) + self.wave = DrawWaveform(self) self.audiograb = AudioGrab_XO175(self.wave.new_buffer, self) elif self.hw == XO1: self.wave = DrawWaveform(self) self.audiograb = AudioGrab_XO1(self.wave.new_buffer, self) else: - self.wave = DrawWaveform(self, channels=2) + self.wave = DrawWaveform(self) self.audiograb = AudioGrab_Unknown(self.wave.new_buffer, self) # no sharing |