示例#1
0
    def __init__(self, logger, audiobackend):
        Qwt.QwtPlotItem.__init__(self)
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
        self.T = 0.
        self.dT = 1.
        self.audiobackend = audiobackend
        #self.previous_time = self.audiobackend.get_stream_time()
        self.offset = 0  #self.audiobackend.get_stream_time()/self.dT

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()
示例#2
0
    def __init__(self):
        self.canvasscaledspectrogram = CanvasScaledSpectrogram()
        self.T = 0.
        self.dT = 1.

        self.jitter_s = 0.

        self.last_data_time = 0.

        self.isPlaying = True

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()

        self.timer = QtCore.QElapsedTimer()
        self.timer.start()

        self.last_time = 0.
示例#3
0
    def __init__(self, logger):
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
        self.T = 0.
        self.dT = 1.

        self.jitter_s = 0.

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()
示例#4
0
	def __init__(self, logger, audiobackend):
		Qwt.QwtPlotItem.__init__(self)
		self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
		self.T = 0.
		self.dT = 1.
		self.audiobackend = audiobackend
		#self.previous_time = self.audiobackend.get_stream_time()
		self.offset = 0 #self.audiobackend.get_stream_time()/self.dT
		
		self.sfft_rate_frac = Fraction(1, 1)
		self.frequency_resampler = Frequency_Resampler()
		self.resampler = Online_Linear_2D_resampler()
示例#5
0
    def __init__(self, logger, audiobackend):
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
        self.T = 0.
        self.dT = 1.
        self.audiobackend = audiobackend

        self.jitter_s = 0.

        self.last_data_time = 0.

        self.isPlaying = True

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()

        self.timer = QtCore.QElapsedTimer()
        self.timer.start()

        self.last_time = 0.
示例#6
0
 def __init__(self, logger):
     Qwt.QwtPlotItem.__init__(self)
     self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
示例#7
0
class PlotImage(Qwt.QwtPlotItem):
    def __init__(self, logger):
        Qwt.QwtPlotItem.__init__(self)
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)

    def addData(self, freq, xyzs, logfreqscale):
        self.canvasscaledspectrogram.setlogfreqscale(logfreqscale)
        self.canvasscaledspectrogram.addData(freq, xyzs)

    def draw(self, painter, xMap, yMap, rect):
        # update the spectrogram according to possibly new canvas dimensions
        self.canvasscaledspectrogram.setcanvas_height(rect.height())
        self.canvasscaledspectrogram.setcanvas_width(rect.width())

        pixmap = self.canvasscaledspectrogram.getpixmap()
        offset = self.canvasscaledspectrogram.getpixmapoffset()

        rolling = True
        if rolling:
            # draw the whole canvas with a selected portion of the pixmap
            painter.drawPixmap(rect.left(), rect.top(), pixmap, offset, 0, 0,
                               0)
        else:
            # draw one single line of the pixmap at a moving position
            painter.drawPixmap(rect.left() + offset, rect.top(), pixmap,
                               offset - 1, 0, 1, 0)

        #print painter
        #print xMap.p1(), xMap.p2(), xMap.s1(), xMap.s2()
        #print yMap.p1(), yMap.p2(), yMap.s1(), yMap.s2()
        #print rect

    def settimerange(self, timerange_seconds):
        self.canvasscaledspectrogram.setT(timerange_seconds)

    def setfreqrange(self, minfreq, maxfreq):
        self.canvasscaledspectrogram.setfreqrange(minfreq, maxfreq)

    def erase(self):
        self.canvasscaledspectrogram.erase()
示例#8
0
class PlotImage:

    def __init__(self):
        self.canvasscaledspectrogram = CanvasScaledSpectrogram()
        self.T = 0.
        self.dT = 1.

        self.jitter_s = 0.

        self.last_data_time = 0.

        self.isPlaying = True

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()

        self.timer = QtCore.QElapsedTimer()
        self.timer.start()

        self.last_time = 0.

    def addData(self, freq, xyzs, logfreqscale, last_data_time):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

        # Note: both the frequency and the time resampler work
        # only on 1D arrays, so we loop on the columns of data.
        # However, we reassemble the 2D output before drawing
        # on the widget's pixmap, because the drawing operation
        # seems to have a costly warmup phase, so it is better
        # to invoke it the fewer number of times possible.

        n = self.resampler.processable(xyzs.shape[1])
        resampled_data = np.zeros((self.frequency_resampler.nsamples, n))

        i = 0
        for j in range(xyzs.shape[1]):
            freq_resampled_data = self.frequency_resampler.process(freq, xyzs[:, j])
            data = self.resampler.process(freq_resampled_data)
            resampled_data[:, i:i + data.shape[1]] = data
            i += data.shape[1]

        self.canvasscaledspectrogram.addData(resampled_data)

        if i > 0:
            self.last_data_time = last_data_time

    def pause(self):
        self.isPlaying = False

    def restart(self):
        self.isPlaying = True
        self.last_time = AudioBackend().get_stream_time()
        self.timer.restart()

    def draw(self, painter, xMap, yMap, rect):
        # update the spectrogram according to possibly new canvas dimensions
        self.frequency_resampler.setnsamples(rect.height())
        self.resampler.set_height(rect.height())
        self.canvasscaledspectrogram.setcanvas_height(rect.height())
        # print self.jitter_s, self.T, rect.width(), rect.width()*(1 + self.jitter_s/self.T)
        jitter_pix = rect.width() * self.jitter_s / self.T
        self.canvasscaledspectrogram.setcanvas_width(rect.width() + jitter_pix)

        screen_rate_frac = Fraction(rect.width(), int(self.T * 1000))
        self.resampler.set_ratio(self.sfft_rate_frac, screen_rate_frac)

        # time advance
        # This function is meant to be called at paintevent time, for better time sync.

        pixmap = self.canvasscaledspectrogram.getpixmap()
        offset = self.canvasscaledspectrogram.getpixmapoffset(delay=jitter_pix / 2)

        if self.isPlaying:
            delta_t = self.timer.nsecsElapsed() * 1e-9
            self.timer.restart()
            pixel_advance = delta_t / (self.T + self.jitter_s) * rect.width()
            self.canvasscaledspectrogram.addPixelAdvance(pixel_advance)

            time = AudioBackend().get_stream_time()
            time_delay = time - self.last_data_time
            pixel_delay = rect.width() * time_delay / self.T

            self.last_time = time

            offset += pixel_delay

        rolling = True
        if rolling:
            # draw the whole canvas with a selected portion of the pixmap

            hints = painter.renderHints()
            # enable bilinear pixmap transformation
            painter.setRenderHints(hints | QtGui.QPainter.SmoothPixmapTransform)
            # Note: nstead of a generic bilinear transformation, a specialized one could be more efficient,
            # since no transformation is needed in y, and the sampling rate is already known to be ok in x.
            sw = rect.width()
            sh = rect.height()

            source_rect = QtCore.QRectF(offset, 0, sw, sh)
            # QRectF since the offset and width may be non-integer
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)
        else:
            sw = rect.width()
            sh = rect.height()
            source_rect = QtCore.QRectF(0, 0, sw, sh)
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)

    def settimerange(self, timerange_seconds, dT):
        self.T = timerange_seconds
        self.dT = dT

    def setfreqrange(self, minfreq, maxfreq):
        self.frequency_resampler.setfreqrange(minfreq, maxfreq)

    def set_sfft_rate(self, rate_frac):
        self.sfft_rate_frac = rate_frac

    def setlogfreqscale(self, logfreqscale):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

    def erase(self):
        self.canvasscaledspectrogram.erase()

    def isOpaque(self):
        return True

    def set_jitter(self, jitter_s):
        self.jitter_s = jitter_s
示例#9
0
class PlotImage(Qwt.QwtPlotItem):
	def __init__(self, logger, audiobackend):
		Qwt.QwtPlotItem.__init__(self)
		self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
		self.T = 0.
		self.dT = 1.
		self.audiobackend = audiobackend
		#self.previous_time = self.audiobackend.get_stream_time()
		self.offset = 0 #self.audiobackend.get_stream_time()/self.dT
		
		self.sfft_rate_frac = Fraction(1, 1)
		self.frequency_resampler = Frequency_Resampler()
		self.resampler = Online_Linear_2D_resampler()

	def addData(self, freq, xyzs, logfreqscale):
		self.frequency_resampler.setlogfreqscale(logfreqscale)

		# Note: both the frequency and the time resampler work
		# only on 1D arrays, so we loop on the columns of data.
		# However, we reassemble the 2D output before drawing
		# on the widget's pixmap, because the drawing operation
		# seems to have a costly warmup phase, so it is better
		# to invoke it the fewer number of times possible.

		n = self.resampler.processable(xyzs.shape[1])
		resampled_data = np.zeros((self.frequency_resampler.nsamples, n))

		i = 0
		for j in range(xyzs.shape[1]):
			freq_resampled_data = self.frequency_resampler.process(freq, xyzs[:, j])
			data = self.resampler.process(freq_resampled_data)
			resampled_data[:,i:i+data.shape[1]] = data
			i += data.shape[1]

		self.canvasscaledspectrogram.addData(resampled_data)

	def draw(self, painter, xMap, yMap, rect):
		# update the spectrogram according to possibly new canvas dimensions
		self.frequency_resampler.setnsamples(rect.height())
		self.resampler.set_height(rect.height())
		self.canvasscaledspectrogram.setcanvas_height(rect.height())
		self.canvasscaledspectrogram.setcanvas_width(rect.width())

		screen_rate_frac = Fraction(rect.width(), int(self.T*1000))
		self.resampler.set_ratio(self.sfft_rate_frac, screen_rate_frac)

		pixmap = self.canvasscaledspectrogram.getpixmap()
		offset = self.canvasscaledspectrogram.getpixmapoffset()
		
		rolling = True
		if rolling:
			# draw the whole canvas with a selected portion of the pixmap

			hints = painter.renderHints()
			# enable bilinear pixmap transformation
			painter.setRenderHints(hints|QtGui.QPainter.SmoothPixmapTransform)
			#FIXME instead of a generic bilinear transformation, I need a specialized one
			# since no transformation is needed in y, and the sampling rate is already known to be ok in x
			sw = rect.width()
			sh = rect.height()

			# this function should be called by repaint, for better time sync

			# FIXME the following is wrong when the display is paused !
			# and even when not paused, it does not improve the smoothness
			# and has a problem of offset
			#current_time = self.audiobackend.get_stream_time()
			#delay = sw*(current_time - self.previous_time)/self.T
			#self.previous_time = current_time
			#self.offset += delay
			#self.offset = (self.offset % sw)
			#offset = self.offset

			source_rect = QtCore.QRectF(offset, 0, sw, sh)
			# QRectF since the offset and width may be non-integer
			painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)
		else:
			sw = rect.width()
			sh = rect.height()
			source_rect = QtCore.QRectF(0, 0, sw, sh)
			painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)

	def settimerange(self, timerange_seconds, dT):
		self.T = timerange_seconds
		self.dT = dT

	def setfreqrange(self, minfreq, maxfreq):
		self.frequency_resampler.setfreqrange(minfreq, maxfreq)

	def set_sfft_rate(self, rate_frac):
		self.sfft_rate_frac = rate_frac

	def setlogfreqscale(self, logfreqscale):
		self.frequency_resampler.setlogfreqscale(logfreqscale)

	def erase(self):
		self.canvasscaledspectrogram.erase()
示例#10
0
	def __init__(self, logger):
		Qwt.QwtPlotItem.__init__(self)
		self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
示例#11
0
class PlotImage(Qwt.QwtPlotItem):
	def __init__(self, logger):
		Qwt.QwtPlotItem.__init__(self)
		self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)

	def addData(self, freq, xyzs, logfreqscale):
		self.canvasscaledspectrogram.setlogfreqscale(logfreqscale)
		self.canvasscaledspectrogram.addData(freq, xyzs)

	def draw(self, painter, xMap, yMap, rect):
		# update the spectrogram according to possibly new canvas dimensions
		self.canvasscaledspectrogram.setcanvas_height(rect.height())
		self.canvasscaledspectrogram.setcanvas_width(rect.width())

		pixmap = self.canvasscaledspectrogram.getpixmap()
		offset = self.canvasscaledspectrogram.getpixmapoffset()
		
		rolling = True
		if rolling:
			# draw the whole canvas with a selected portion of the pixmap
			painter.drawPixmap(rect.left(), rect.top(), pixmap,  offset,  0,  0,  0)
		else:
			# draw one single line of the pixmap at a moving position
			painter.drawPixmap(rect.left() + offset, rect.top(), pixmap,  offset-1,  0,  1,  0)
		
		#print painter
		#print xMap.p1(), xMap.p2(), xMap.s1(), xMap.s2()
		#print yMap.p1(), yMap.p2(), yMap.s1(), yMap.s2()
		#print rect

	def settimerange(self, timerange_seconds):
		self.canvasscaledspectrogram.setT(timerange_seconds)

	def setfreqrange(self, minfreq, maxfreq):
		self.canvasscaledspectrogram.setfreqrange(minfreq, maxfreq)

	def erase(self):
		self.canvasscaledspectrogram.erase()
示例#12
0
class PlotImage(Qwt.QwtPlotItem):
    def __init__(self, logger, audiobackend):
        Qwt.QwtPlotItem.__init__(self)
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
        self.T = 0.
        self.dT = 1.
        self.audiobackend = audiobackend
        #self.previous_time = self.audiobackend.get_stream_time()
        self.offset = 0  #self.audiobackend.get_stream_time()/self.dT

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()

    def addData(self, freq, xyzs, logfreqscale):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

        # Note: both the frequency and the time resampler work
        # only on 1D arrays, so we loop on the columns of data.
        # However, we reassemble the 2D output before drawing
        # on the widget's pixmap, because the drawing operation
        # seems to have a costly warmup phase, so it is better
        # to invoke it the fewer number of times possible.

        n = self.resampler.processable(xyzs.shape[1])
        resampled_data = np.zeros((self.frequency_resampler.nsamples, n))

        i = 0
        for j in range(xyzs.shape[1]):
            freq_resampled_data = self.frequency_resampler.process(
                freq, xyzs[:, j])
            data = self.resampler.process(freq_resampled_data)
            resampled_data[:, i:i + data.shape[1]] = data
            i += data.shape[1]

        self.canvasscaledspectrogram.addData(resampled_data)

    def draw(self, painter, xMap, yMap, rect):
        # update the spectrogram according to possibly new canvas dimensions
        self.frequency_resampler.setnsamples(rect.height())
        self.resampler.set_height(rect.height())
        self.canvasscaledspectrogram.setcanvas_height(rect.height())
        self.canvasscaledspectrogram.setcanvas_width(rect.width())

        screen_rate_frac = Fraction(rect.width(), int(self.T * 1000))
        self.resampler.set_ratio(self.sfft_rate_frac, screen_rate_frac)

        pixmap = self.canvasscaledspectrogram.getpixmap()
        offset = self.canvasscaledspectrogram.getpixmapoffset()

        rolling = True
        if rolling:
            # draw the whole canvas with a selected portion of the pixmap

            hints = painter.renderHints()
            # enable bilinear pixmap transformation
            painter.setRenderHints(hints
                                   | QtGui.QPainter.SmoothPixmapTransform)
            #FIXME instead of a generic bilinear transformation, I need a specialized one
            # since no transformation is needed in y, and the sampling rate is already known to be ok in x
            sw = rect.width()
            sh = rect.height()

            # this function should be called by repaint, for better time sync

            # FIXME the following is wrong when the display is paused !
            # and even when not paused, it does not improve the smoothness
            # and has a problem of offset
            #current_time = self.audiobackend.get_stream_time()
            #delay = sw*(current_time - self.previous_time)/self.T
            #self.previous_time = current_time
            #self.offset += delay
            #self.offset = (self.offset % sw)
            #offset = self.offset

            source_rect = QtCore.QRectF(offset, 0, sw, sh)
            # QRectF since the offset and width may be non-integer
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)
        else:
            sw = rect.width()
            sh = rect.height()
            source_rect = QtCore.QRectF(0, 0, sw, sh)
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)

    def settimerange(self, timerange_seconds, dT):
        self.T = timerange_seconds
        self.dT = dT

    def setfreqrange(self, minfreq, maxfreq):
        self.frequency_resampler.setfreqrange(minfreq, maxfreq)

    def set_sfft_rate(self, rate_frac):
        self.sfft_rate_frac = rate_frac

    def setlogfreqscale(self, logfreqscale):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

    def erase(self):
        self.canvasscaledspectrogram.erase()
示例#13
0
class PlotImage(Qwt.QwtPlotItem):
	def __init__(self, logger, audiobackend):
		Qwt.QwtPlotItem.__init__(self)
		self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
		self.T = 0.
		self.dT = 1.
		self.audiobackend = audiobackend
		#self.previous_time = self.audiobackend.get_stream_time()
		self.offset = 0 #self.audiobackend.get_stream_time()/self.dT
		
		self.jitter_s = 0.

		self.isPlaying = True

		self.sfft_rate_frac = Fraction(1, 1)
		self.frequency_resampler = Frequency_Resampler()
		self.resampler = Online_Linear_2D_resampler()

		self.timer = QtCore.QElapsedTimer()
		self.timer.start()

	def addData(self, freq, xyzs, logfreqscale):
		self.frequency_resampler.setlogfreqscale(logfreqscale)

		# Note: both the frequency and the time resampler work
		# only on 1D arrays, so we loop on the columns of data.
		# However, we reassemble the 2D output before drawing
		# on the widget's pixmap, because the drawing operation
		# seems to have a costly warmup phase, so it is better
		# to invoke it the fewer number of times possible.

		n = self.resampler.processable(xyzs.shape[1])
		resampled_data = np.zeros((self.frequency_resampler.nsamples, n))

		i = 0
		for j in range(xyzs.shape[1]):
			freq_resampled_data = self.frequency_resampler.process(freq, xyzs[:, j])
			data = self.resampler.process(freq_resampled_data)
			resampled_data[:,i:i+data.shape[1]] = data
			i += data.shape[1]

		self.canvasscaledspectrogram.addData(resampled_data)

	def pause(self):
		self.isPlaying = False

	def restart(self):
		self.isPlaying = True
		self.timer.restart()

	def draw(self, painter, xMap, yMap, rect):
		# update the spectrogram according to possibly new canvas dimensions
		self.frequency_resampler.setnsamples(rect.height())
		self.resampler.set_height(rect.height())
		self.canvasscaledspectrogram.setcanvas_height(rect.height())
		#print self.jitter_s, self.T, rect.width(), rect.width()*(1 + self.jitter_s/self.T)
		jitter_pix = rect.width()*self.jitter_s/self.T
		self.canvasscaledspectrogram.setcanvas_width(rect.width() + jitter_pix)

		screen_rate_frac = Fraction(rect.width(), int(self.T*1000))
		self.resampler.set_ratio(self.sfft_rate_frac, screen_rate_frac)

		# time advance
		# FIXME ideally this function should be called at paintevent time, for better time sync
		# but I'm not sure it is... maybe qwt does some sort of double-buffering
		# and repaints its items outside of paintevents
		# solution: look at PaintEvent

		# FIXME there is a small bands of columns with jitter (on both sides of the spectrogram)
		# solution: grow the rolling-canvas by a couple of columns,
		# and slightly delay the spectrogram by the same number of columns

		if self.isPlaying:
			delta_t = self.timer.nsecsElapsed()*1e-9
			self.timer.restart()
			pixel_advance = delta_t/(self.T + self.jitter_s)*rect.width()
			self.canvasscaledspectrogram.addPixelAdvance(pixel_advance)

		pixmap = self.canvasscaledspectrogram.getpixmap()
		offset = self.canvasscaledspectrogram.getpixmapoffset(delay=jitter_pix/2)
		
		rolling = True
		if rolling:
			# draw the whole canvas with a selected portion of the pixmap

			hints = painter.renderHints()
			# enable bilinear pixmap transformation
			painter.setRenderHints(hints|QtGui.QPainter.SmoothPixmapTransform)
			#FIXME instead of a generic bilinear transformation, I need a specialized one
			# since no transformation is needed in y, and the sampling rate is already known to be ok in x
			sw = rect.width()
			sh = rect.height()

			source_rect = QtCore.QRectF(offset, 0, sw, sh)
			# QRectF since the offset and width may be non-integer
			painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)
		else:
			sw = rect.width()
			sh = rect.height()
			source_rect = QtCore.QRectF(0, 0, sw, sh)
			painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)

	def settimerange(self, timerange_seconds, dT):
		self.T = timerange_seconds
		self.dT = dT

	def setfreqrange(self, minfreq, maxfreq):
		self.frequency_resampler.setfreqrange(minfreq, maxfreq)

	def set_sfft_rate(self, rate_frac):
		self.sfft_rate_frac = rate_frac

	def setlogfreqscale(self, logfreqscale):
		self.frequency_resampler.setlogfreqscale(logfreqscale)

	def erase(self):
		self.canvasscaledspectrogram.erase()

	def set_jitter(self, jitter_s):
		self.jitter_s = jitter_s
示例#14
0
class PlotImage:

    def __init__(self, logger, audiobackend):
        self.canvasscaledspectrogram = CanvasScaledSpectrogram(logger)
        self.T = 0.
        self.dT = 1.
        self.audiobackend = audiobackend

        self.jitter_s = 0.

        self.last_data_time = 0.

        self.isPlaying = True

        self.sfft_rate_frac = Fraction(1, 1)
        self.frequency_resampler = Frequency_Resampler()
        self.resampler = Online_Linear_2D_resampler()

        self.timer = QtCore.QElapsedTimer()
        self.timer.start()

        self.last_time = 0.

    def addData(self, freq, xyzs, logfreqscale, last_data_time):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

        # Note: both the frequency and the time resampler work
        # only on 1D arrays, so we loop on the columns of data.
        # However, we reassemble the 2D output before drawing
        # on the widget's pixmap, because the drawing operation
        # seems to have a costly warmup phase, so it is better
        # to invoke it the fewer number of times possible.

        n = self.resampler.processable(xyzs.shape[1])
        resampled_data = np.zeros((self.frequency_resampler.nsamples, n))

        i = 0
        for j in range(xyzs.shape[1]):
            freq_resampled_data = self.frequency_resampler.process(freq, xyzs[:, j])
            data = self.resampler.process(freq_resampled_data)
            resampled_data[:, i:i + data.shape[1]] = data
            i += data.shape[1]

        self.canvasscaledspectrogram.addData(resampled_data)

        if i > 0:
            self.last_data_time = last_data_time

    def pause(self):
        self.isPlaying = False

    def restart(self):
        self.isPlaying = True
        self.timer.restart()

    def draw(self, painter, xMap, yMap, rect):
        # update the spectrogram according to possibly new canvas dimensions
        self.frequency_resampler.setnsamples(rect.height())
        self.resampler.set_height(rect.height())
        self.canvasscaledspectrogram.setcanvas_height(rect.height())
        # print self.jitter_s, self.T, rect.width(), rect.width()*(1 + self.jitter_s/self.T)
        jitter_pix = rect.width() * self.jitter_s / self.T
        self.canvasscaledspectrogram.setcanvas_width(rect.width() + jitter_pix)

        screen_rate_frac = Fraction(rect.width(), int(self.T * 1000))
        self.resampler.set_ratio(self.sfft_rate_frac, screen_rate_frac)

        # time advance
        # This function is meant to be called at paintevent time, for better time sync.

        pixmap = self.canvasscaledspectrogram.getpixmap()
        offset = self.canvasscaledspectrogram.getpixmapoffset(delay=jitter_pix / 2)

        if self.isPlaying:
            delta_t = self.timer.nsecsElapsed() * 1e-9
            self.timer.restart()
            pixel_advance = delta_t / (self.T + self.jitter_s) * rect.width()
            self.canvasscaledspectrogram.addPixelAdvance(pixel_advance)

            time = self.audiobackend.get_stream_time()
            time_delay = time - self.last_data_time
            pixel_delay = rect.width() * time_delay / self.T

            draw_delay = time - self.last_time

            self.last_time = time

            offset += pixel_delay

        rolling = True
        if rolling:
            # draw the whole canvas with a selected portion of the pixmap

            hints = painter.renderHints()
            # enable bilinear pixmap transformation
            painter.setRenderHints(hints | QtGui.QPainter.SmoothPixmapTransform)
            # Note: nstead of a generic bilinear transformation, a specialized one could be more efficient,
            # since no transformation is needed in y, and the sampling rate is already known to be ok in x.
            sw = rect.width()
            sh = rect.height()

            source_rect = QtCore.QRectF(offset, 0, sw, sh)
            # QRectF since the offset and width may be non-integer
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)
        else:
            sw = rect.width()
            sh = rect.height()
            source_rect = QtCore.QRectF(0, 0, sw, sh)
            painter.drawPixmap(QtCore.QRectF(rect), pixmap, source_rect)

    def settimerange(self, timerange_seconds, dT):
        self.T = timerange_seconds
        self.dT = dT

    def setfreqrange(self, minfreq, maxfreq):
        self.frequency_resampler.setfreqrange(minfreq, maxfreq)

    def set_sfft_rate(self, rate_frac):
        self.sfft_rate_frac = rate_frac

    def setlogfreqscale(self, logfreqscale):
        self.frequency_resampler.setlogfreqscale(logfreqscale)

    def erase(self):
        self.canvasscaledspectrogram.erase()

    def isOpaque(self):
        return True

    def set_jitter(self, jitter_s):
        self.jitter_s = jitter_s