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 __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()
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.
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.last_time = self.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 = 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
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