Exemplo n.º 1
0
class Visualizer(QMainWindow):
    
    def __init__(self):
        
        super().__init__()
        self.initUI()
        self._buflen = 1440 # 4096


    def initUI(self):
        
        # main window/layout
        window = QWidget()
        layout = QVBoxLayout()
        
        # layout for audio device and sample rate selection
        deviceLayout = QHBoxLayout()
        
        # make audio device selection box and list of available devices
        self.deviceBox = QComboBox()
        defaultDeviceInfo = QAudioDeviceInfo.defaultInputDevice()
        self.availableDevices = [defaultDeviceInfo]
        self.availableDevices += QAudioDeviceInfo.availableDevices(
                                                             QAudio.AudioInput)
        for device in self.availableDevices:
            self.deviceBox.addItem(device.deviceName())
            
        # make sample rate label and combobox
        sRateLabel = QLabel("Sample rate:")
        sRateLabel.setAlignment(Qt.AlignRight)
        
        # user can choose between 44.1 and 48kHz (valid DetectorBank rates)
        self.sRateBox = QComboBox()
        self.sRateBox.addItem("44100")
        self.sRateBox.addItem("48000")
        self.sRateBox.setCurrentIndex(1)
        
        # add device and sr widgets to device layout
        deviceLayout.addWidget(self.deviceBox)
        deviceLayout.addWidget(sRateLabel)
        deviceLayout.addWidget(self.sRateBox)
        
        # add device layout to main layout
        layout.addLayout(deviceLayout)
        
        # DetectorBank parameters layout
        # two rows of three parameters
        # each param needs label and edit, 
        # and a 'Start' button will be added at the bottom
        # so grid should be 3x6
        detBankParamLayout = QGridLayout()
        
        # label and lineedit for each
        bandwidthLabel = QLabel("Bandwidth (cents):")
        dampingLabel = QLabel("Damping:")
        gainLabel = QLabel("Gain:")
        edoLabel = QLabel("EDO:")
        lwrLabel = QLabel("Lower note:")
        uprLabel = QLabel("Upper note:")
        
        self.bandwidthEdit = QLineEdit("0")
        self.dampingEdit = QLineEdit("0.0001")
        self.gainEdit = QLineEdit("25")
        self.edoEdit = QLineEdit("12")
        self.lwrEdit = QLineEdit("A1")
        self.uprEdit = QLineEdit("A7")
        
        # store all in lists
        detBankParamLabels = [bandwidthLabel, dampingLabel, gainLabel, 
                              edoLabel, lwrLabel, uprLabel]
        
        detBankParamEdits = [self.bandwidthEdit, self.dampingEdit, 
                             self.gainEdit, self.edoEdit, self.lwrEdit, 
                             self.uprEdit]
         
        # fill first two rows of grid with labels and edits
        row = 0

        for row in range(2):
            widgetNum = 0
        
            for i in range((row*3), (row*3)+3):
                detBankParamLayout.addWidget(detBankParamLabels[i], row, 
                                             widgetNum)
                widgetNum += 1
                detBankParamLayout.addWidget(detBankParamEdits[i], row, 
                                             widgetNum)
                widgetNum += 1
            
        # align labels to the right (next to the edit)
        for i in range(len(detBankParamLabels)):
            detBankParamLabels[i].setAlignment(Qt.AlignRight)
                
        # button to make DetectorBank and start visualisation
        row += 1
        startButton = QPushButton("&Start!")
        detBankParamLayout.addWidget(startButton, row, 5)
        startButton.clicked.connect(self.start)
        
        # add grid of detbank params (and start button) to main layout
        layout.addLayout(detBankParamLayout)
        
        window.setLayout(layout)
        self.setCentralWidget(window)
        self.show()
        
        
    def initializeAudio(self, deviceInfo):
        """ Make a QAudioInput from the given device """
                
        # make buffers of 40ms of samples
        self.refRate = 0.04
        
        # mono, 32-bit float audio
        fmt = QAudioFormat()
        fmt.setSampleRate(self.getSampleRate())
        fmt.setChannelCount(1)
        fmt.setSampleSize(32)
        fmt.setSampleType(QAudioFormat.Float)
        fmt.setByteOrder(QAudioFormat.LittleEndian)
        fmt.setCodec("audio/pcm")
        
        if not deviceInfo.isFormatSupported(fmt):
            fmt = deviceInfo.nearestFormat(fmt)
            
        self.audioInput = QAudioInput(deviceInfo, fmt)
        self.audioInput.setBufferSize(4*self.buflen) # set size in bytes

        
    def startAudio(self):
        self.audioDevice = self.audioInput.start()
        self.audioDevice.readyRead.connect(self.updatePlot)
        
        
    def start(self):
        """ Initialise audio, make DetectorBank, open PlotData window and 
            start audio 
        """
        
        print('Initializing audio...')
        deviceIdx = self.deviceBox.currentIndex()
        device = self.availableDevices[deviceIdx]
        self.initializeAudio(device)
        
        print('Making DetectorBank...')
        pitchOffset = self.makeDetectorBank()
        
        print('Making PlotData object...')
        self.pd = PlotData(self.db.getChans(), pitchOffset)
#        self.pd.show()
        
        print('Starting audio...')
        self.startAudio()
        
    
    def updatePlot(self):
        
        # get data as float32
        # 4*buflen is number of bytes
        data = self.audioDevice.read(4*self.buflen)
        data = np.frombuffer(data, dtype=np.int16)
        data = np.array(data/2**15, dtype=np.dtype('float32'))
        
        # set DetectorBank input
        self.db.setInputBuffer(data)
          
        # fill z with detector output
        self.db.getZ(self.z)
        
#        self.db.absZ(self.r, self.z)
        
        self.pd.update(self.z)
        
#        self.close()
        
        
    def makeDetectorBank(self):
        """ Make DetectorBank from given parameters """
        
        sr = self.getSampleRate()
        bandwidth_cents = float(self.bandwidthEdit.text())
        dmp = float(self.dampingEdit.text())
        gain = float(self.gainEdit.text())
        edo = float(self.edoEdit.text())
        lwr = self.lwrEdit.text()
        upr = self.uprEdit.text()
        
        lwr, pitchOffset = getNoteNum(lwr, edo)
        upr, _ = getNoteNum(upr, edo)
        upr += 1 # include upr note in DetectorBank
        
        # make and fill frequency and bandwidth arrays
        freq = np.zeros(int(upr-lwr))
        bw = np.zeros(len(freq))
        for i in range(len(freq)):
            k = lwr+i
            freq[i] = 440*2**(k/edo)
            # if non-minimum bandwidth detectors requested, find B in Hz
            if bandwidth_cents != 0:
                bw[i] = centsToHz(freq[i], bandwidth_cents, edo)
                
        # combine into stacked array
        det_char = np.stack((freq,bw), axis=1)
        
        # (almost) empty input buffer
        buffer = np.zeros(1, dtype=np.float32)
        
        # DetectorBank features
        method = DetectorBank.runge_kutta
        f_norm = DetectorBank.freq_unnormalized
        a_norm = DetectorBank.amp_unnormalized
        
        self.db = DetectorBank(sr, buffer, 4, det_char, method|f_norm|a_norm, 
                                dmp, gain)
        
        # create empty output array
        self.z = np.zeros((int(self.db.getChans()),self.buflen), 
                          dtype=np.complex128)
        
        self.r = np.zeros(self.z.shape)
        
        print("Made DetectorBank with {} channels, with a sample rate of {}Hz"
              .format(self.db.getChans(), self.db.getSR()))
        
        return pitchOffset
        
    ## get and/or set various values
    def getSampleRate(self, returnType=int):
        return returnType(self.sRateBox.currentText())
    
    @property
    def refreshRate(self):
        return self._refRate
    
    @refreshRate.setter
    def refreshRate(self, value):
        self._refRate = value
        self.buflen = self._refRate * self.getSampleRate()
    
    @property
    def buflen(self):
        return self._buflen
        
    @buflen.setter
    def buflen(self, value):
        self._buflen = int(value)
Exemplo n.º 2
0
    gain = 50
    
    f0 = 440*2**(-2/12)
    
    # select and make critical band
    band_types = ['1Hz-spaced', 'EDO']
    band_type = band_types[1]
    num = 21 # 31 #
    f = make_band(f0, band_type, num)
    
    bandwidth = np.zeros(len(f))
    det_char = np.array(list(zip(f, bandwidth)))
    det = DetectorBank(sr, audio.astype(np.float32), 4, det_char,
                       method|f_norm|a_norm, d, gain)
    
    chans = det.getChans()
    p = Producer(det)
    cache = DetectorCache(p, 2, sr//2)
    
    r = np.zeros(len(audio))
    for i in range(len(r)):
        for k in range(chans):
            r[i] += np.log(cache[k,i]) #cache[k,i] # 
        r[i] /= chans
    
    t = np.linspace(0, len(audio)/sr, len(audio))
    
    plt.plot(t[i0:i1], r[i0:i1])

    onset = int(onset_t * sr)
    plt.axvline(x=onset/sr, color='red', linestyle='--')
Exemplo n.º 3
0
f0 = 440*2**(1/12)

hwidth = 10
step = 1
    
    
f = np.arange(f0-hwidth, f0+hwidth+step, step)

bandwidth = np.zeros(len(f))
det_char = np.array(list(zip(f, bandwidth)))
det = DetectorBank(sr, audio.astype(np.float32), 4, det_char, 
                   method|f_norm|a_norm, d, gain)

buflen = det.getBuflen()

channels = det.getChans()

z = np.zeros((len(f),len(audio)), dtype=np.complex128)
r = np.zeros(z.shape)
det.seek(0)
det.getZ(z)
m = det.absZ(r, z)

######## matching straight line and decaying exponential

## get portion of response that corresponds to single note
#t = np.linspace(0, len(audio), len(audio))
t0 = 6*sr
t1 = int(9*sr)
#ts = t[t0:t1]
rs = r[-1][t0:t1]
Exemplo n.º 4
0
def plotMean(audio, sr, freq, onset, found, sp):

    sns.set_style('whitegrid')

    if audio.ndim > 1:
        audio = np.mean(audio, axis=1)

    offset = 1 / 4
    pad = np.zeros(int(sr * offset))
    #    pad.fill(audio[0])

    audio = np.append(pad, audio)

    params = getParams()
    method = params['method']
    f_norm = params['f_norm']
    a_norm = params['a_norm']
    d = params['damping']
    gain = params['gain']

    bw = params['real_bandwidth']
    edo = params['edo']

    f = makeBand(freq, bw, edo)

    bandwidth = np.zeros(len(f))
    det_char = np.array(list(zip(f, bandwidth)))

    det = DetectorBank(sr, audio.astype(np.float32), 4, det_char,
                       method | f_norm | a_norm, d, gain)

    z = np.zeros((len(f), len(audio)), dtype=np.complex128)
    det.getZ(z)

    r = np.zeros(z.shape)
    det.absZ(r, z)

    meanlog = np.zeros(len(audio))

    for n in range(len(meanlog)):
        mean = 0
        for k in range(det.getChans()):
            mean += zeroLog(r[k, n])
        meanlog[n] = mean

    t = np.linspace(0, len(audio) / sr, len(audio))

    t0 = 0.25
    t1 = 0.5

    i0 = int(sr * t0)
    i1 = int(sr * t1)

    plt.figure()
    plt.plot(t[i0:i1], meanlog[i0:i1])

    plt.axvline(onset + offset, color='lime')  # linestyle='--', )
    for t in found:
        plt.axvline(t + offset, linestyle='--', color='red')

    ax = plt.gca()
    xtx = ax.get_xticks()
    xtxlab = ['{:.0f}'.format(1000 * (item - offset)) for item in xtx]
    ax.set_xticklabels(xtxlab)

    #    plt.title('{:.3f}Hz'.format(freq))
    plt.xlabel('Time (ms)')
    #    plt.ylabel('Log(|z|)')
    plt.ylabel('Mean log')
    plt.grid(True)

    sp.plot(plt)