''' The MIT License (MIT) Copyright (c) 2017 Sean UN Wood Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @author: Sean UN Wood ''' import logging from os import listdir from os.path import join, isdir from collections import OrderedDict import numpy as np from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg from gccNMF.realtime.gccNMFProcessor import TARGET_MODE_BOXCAR, TARGET_MODE_MULTIPLE, TARGET_MODE_WINDOW_FUNCTION BUTTON_WIDTH = 50 class RealtimeGCCNMFInterfaceWindow(QtGui.QMainWindow): def __init__(self, audioPath, numTDOAs, gccPHATNLAlpha, gccPHATNLEnabled, dictionariesW, dictionarySize, dictionarySizes, dictionaryType, numHUpdates, localizationEnabled, localizationWindowSize, gccPHATHistory, tdoaHistory, inputSpectrogramHistory, outputSpectrogramHistory, coefficientMaskHistories, togglePlayAudioProcessQueue, togglePlayAudioProcessAck, togglePlayGCCNMFProcessQueue, togglePlayGCCNMFProcessAck, tdoaParamsGCCNMFProcessQueue, tdoaParamsGCCNMFProcessAck, toggleSeparationGCCNMFProcessQueue, toggleSeparationGCCNMFProcessAck): super(RealtimeGCCNMFInterfaceWindow, self).__init__() self.audioPath = audioPath logging.info('Loading interface with audio path: %s' % self.audioPath) self.initAudioFiles() self.numTDOAs = numTDOAs self.tdoaIndexes = np.arange(numTDOAs) self.dictionariesW = getVisualizedDictionariesW(dictionariesW) self.dictionaryTypes = self.dictionariesW.keys() self.dictionarySize = dictionarySize self.dictionarySizes = dictionarySizes self.dictionaryType = dictionaryType self.numHUpdates = numHUpdates self.targetTDOAIndex = self.numTDOAs / 2.0 self.targetTDOAEpsilon = self.numTDOAs / 10.0 self.gccPHATNLAlpha = gccPHATNLAlpha self.gccPHATNLEnabled = gccPHATNLEnabled self.localizationEnabled = localizationEnabled self.localizationWindowSize = localizationWindowSize self.gccPHATPlotTimer = QtCore.QTimer() self.gccPHATPlotTimer.timeout.connect(self.updateGCCPHATPlot) self.gccPHATHistory = gccPHATHistory self.gccPHATHistorySize = gccPHATHistory.size() self.tdoaHistory = tdoaHistory self.inputSpectrogramHistory = inputSpectrogramHistory self.outputSpectrogramHistory = outputSpectrogramHistory self.coefficientMaskHistories = coefficientMaskHistories self.togglePlayAudioProcessQueue = togglePlayAudioProcessQueue self.togglePlayAudioProcessAck = togglePlayAudioProcessAck self.togglePlayGCCNMFProcessQueue = togglePlayGCCNMFProcessQueue self.togglePlayGCCNMFProcessAck = togglePlayGCCNMFProcessAck self.tdoaParamsGCCNMFProcessQueue = tdoaParamsGCCNMFProcessQueue self.tdoaParamsGCCNMFProcessAck = tdoaParamsGCCNMFProcessAck self.toggleSeparationGCCNMFProcessQueue = toggleSeparationGCCNMFProcessQueue self.toggleSeparationGCCNMFProcessAck = toggleSeparationGCCNMFProcessAck self.playIconString = 'Play' self.pauseIconString = 'Pause' self.separationOffIconString = 'Disabled' self.separationOnIconString = 'Enabled' '''self.playIconString = u'\u23F5' self.pauseIconString = u'\u23F8' self.separationOffIconString = u'\u21F6 | \u21F6' self.separationOnIconString = u'\u21F6 | \u2192''' self.targetModeIconStrings = {TARGET_MODE_BOXCAR: u'\u168B', TARGET_MODE_MULTIPLE: u'\u168D', TARGET_MODE_WINDOW_FUNCTION: u'\u1109'} self.rollingImages = True self.initWindow() self.initControlWidgets() self.initVisualizationWidgets() self.initWindowLayout() self.localizationStateChanged() #self.show() self.showMaximized() def keyPressEvent(self, event): key = event.key() if key == QtCore.Qt.Key_Escape: if self.isFullScreen(): self.showNormal() else: self.close() if key == QtCore.Qt.Key_W and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.close() elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter or key == QtCore.Qt.Key_Space: self.togglePlay() elif key == QtCore.Qt.Key_F and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: if self.isFullScreen(): self.showNormal() #self.showMaximized() else: self.showFullScreen() elif key == QtCore.Qt.Key_I and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.toggleInfoViews() elif key == QtCore.Qt.Key_1 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.inputSpectrogramWidget.setVisible(self.inputSpectrogramWidget.isHidden()) elif key == QtCore.Qt.Key_2 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.outputSpectrogramWidget.setVisible(self.outputSpectrogramWidget.isHidden()) elif key == QtCore.Qt.Key_3 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.dictionaryWidget.setVisible(self.dictionaryWidget.isHidden()) elif key == QtCore.Qt.Key_4 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.coefficientMaskWidget.setVisible(self.coefficientMaskWidget.isHidden()) elif key == QtCore.Qt.Key_5 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.gccPHATHistoryWidget.setVisible(self.gccPHATHistoryWidget.isHidden()) elif key == QtCore.Qt.Key_0 and QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: self.rollingImages = not self.rollingImages super(QtGui.QMainWindow, self).keyPressEvent(event) def closeEvent(self, event): logging.info('RealtimeGCCNMFInterfaceWindow: closing...') self.gccPHATPlotTimer.stop() def initAudioFiles(self): if isdir(self.audioPath): audioDirectory = self.audioPath self.audioFilePaths = [join(audioDirectory, fileName) for fileName in listdir(audioDirectory) if fileName.endswith('wav')] elif self.audioPath.endswith('.wav'): self.audioFilePaths = [self.audioPath] else: raise IOError('Unable to find wav files at: %s' % self.audioPath) self.selectedFileIndex = 0 def initWindow(self): self.setWindowTitle('Real-time GCC-NMF') self.mainWidget = QtGui.QWidget() self.setCentralWidget(self.mainWidget) self.backgroundColor = self.mainWidget.palette().color(QtGui.QPalette.Background) self.borderColor = 'k' self.mainWidget.setStyleSheet('QSplitter::handle {image: url(images/notExists.png); background-color: #D8D8D8}') self.mainLayout = QtGui.QGridLayout() self.mainWidget.setLayout(self.mainLayout) self.mainWidget.setAutoFillBackground(True) p = QtGui.QPalette(self.mainWidget.palette()) p.setColor(self.mainWidget.backgroundRole(), QtCore.Qt.black) self.mainWidget.setPalette(p) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(1) def initWindowLayout(self): sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) self.infoLabelWidgets = [] def addWidgetWithLabel(widget, label, fromRow, fromColumn, rowSpan=1, columnSpan=1): labeledWidget = QtGui.QWidget() widgetLayout = QtGui.QVBoxLayout() widgetLayout.setContentsMargins(0, 0, 0, 0) widgetLayout.setSpacing(1) labeledWidget.setLayout(widgetLayout) labelWidget = QtGui.QLabel(label) labelWidget.setContentsMargins(0, 3, 0, 1) labelWidget.setAutoFillBackground(True) labelWidget.setAlignment(QtCore.Qt.AlignCenter) #labelWidget.setStyleSheet('QLabel { border-top-width: 10px }') self.infoLabelWidgets.append(labelWidget) widgetLayout.addWidget(labelWidget) widgetLayout.addWidget(widget) labeledWidget.setSizePolicy(sizePolicy) self.mainLayout.addWidget(labeledWidget, fromRow, fromColumn, rowSpan, columnSpan) addWidgetWithLabel(self.inputSpectrogramWidget, 'Input Spectrogram', 0, 1) addWidgetWithLabel(self.outputSpectrogramWidget, 'Output Spectrogram', 1, 1) addWidgetWithLabel(self.controlsWidget, 'GCC-NMF Masking Function', 0, 2) addWidgetWithLabel(self.gccPHATHistoryWidget, 'GCC PHAT Angular Spectrogram', 0, 3) addWidgetWithLabel(self.dictionaryWidget, 'NMF Dictionary', 1, 2) addWidgetWithLabel(self.coefficientMaskWidget, 'NMF Dictionary Mask', 1, 3) #for widget in self.infoLabelWidgets: # widget.hide() #map(lambda widget: widget.hide(), self.infoLabelWidgets) def initControlWidgets(self): self.initMaskFunctionControls() self.initMaskFunctionPlot() self.initNMFControls() self.initLocalizationControls() self.initUIControls() controlWidgetsLayout = QtGui.QVBoxLayout() controlWidgetsLayout.addWidget(self.gccPHATPlotWidget) controlWidgetsLayout.addLayout(self.maskFunctionControlslayout) self.addSeparator(controlWidgetsLayout) controlWidgetsLayout.addLayout(self.nmfControlsLayout) controlWidgetsLayout.addLayout(self.localizationControlsLayout) self.addSeparator(controlWidgetsLayout) controlWidgetsLayout.addWidget(self.uiConrolsWidget) self.controlsWidget = QtGui.QWidget() self.controlsWidget.setLayout(controlWidgetsLayout) self.controlsWidget.setAutoFillBackground(True) def initMaskFunctionControls(self): self.maskFunctionControlslayout = QtGui.QHBoxLayout() labelsLayout = QtGui.QVBoxLayout() slidersLayout = QtGui.QVBoxLayout() self.maskFunctionControlslayout.addLayout(labelsLayout) self.maskFunctionControlslayout.addLayout(slidersLayout) def addSlider(label, changedFunction, minimum, maximum, value): labelWidget = QtGui.QLabel(label) labelsLayout.addWidget(labelWidget) slider = QtGui.QSlider(QtCore.Qt.Horizontal) slider.setMinimum(minimum) slider.setMaximum(maximum) slider.setValue(value) slider.sliderReleased.connect(changedFunction) slidersLayout.addWidget(slider) return slider, labelWidget self.targetModeWindowTDOASlider, self.targetModeWindowTDOALabel = addSlider('Center:', self.tdoaRegionChanged, 0, 100, 50) self.targetModeWindowWidthSlider, _ = addSlider('Width:', self.tdoaRegionChanged, 1, 101, 50) self.targetModeWindowBetaSlider, _ = addSlider('Shape:', self.tdoaRegionChanged, 0, 100, 50) self.targetModeWindowNoiseFloorSlider, _ = addSlider('Floor:', self.tdoaRegionChanged, 0, 100, 0) def initMaskFunctionPlot(self): self.gccPHATPlotWidget = self.createGraphicsLayoutWidget(self.backgroundColor, contentMargins=(6, 12, 18, 10)) self.gccPHATPlotItem = self.gccPHATPlotWidget.addPlot() self.gccPHATPlotItem.getViewBox().setBackgroundColor((255, 255, 255, 150)) self.gccPHATPlot = self.gccPHATPlotItem.plot() self.gccPHATPlot.setPen((0, 0, 0)) self.gccPHATPlotItem.hideAxis('left') self.gccPHATPlotItem.hideAxis('bottom') self.gccPHATPlotItem.hideButtons() self.gccPHATPlotItem.setXRange(0, self.numTDOAs - 1) self.targetTDOARegion = pg.LinearRegionItem([self.targetTDOAIndex - self.targetTDOAEpsilon, self.targetTDOAIndex + self.targetTDOAEpsilon], bounds=[0, self.numTDOAs - 1], movable=True) self.targetTDOARegion.sigRegionChangeFinished.connect(self.tdoaRegionChanged) self.targetWindowFunctionPen = pg.mkPen((0, 0, 204, 255), width=2) # , style=QtCore.Qt.DashLine) self.targetWindowFunctionPlot = TargetWindowFunctionPlot(self.targetTDOARegion, self.targetModeWindowTDOASlider, self.targetModeWindowBetaSlider, self.targetModeWindowNoiseFloorSlider, self.targetModeWindowWidthSlider, self.numTDOAs, pen=self.targetWindowFunctionPen) self.gccPHATPlotItem.addItem(self.targetWindowFunctionPlot) self.targetWindowFunctionPlot.updateData() def initNMFControls(self): self.nmfControlsLayout = QtGui.QHBoxLayout() self.nmfControlsLayout.addStretch(1) self.nmfControlsLayout.addWidget(QtGui.QLabel('Dictionary Size:')) self.dictionarySizeDropDown = QtGui.QComboBox() for dictionarySize in self.dictionarySizes: self.dictionarySizeDropDown.addItem( str(dictionarySize) ) self.dictionarySizeDropDown.setMaximumWidth(75) self.dictionarySizeDropDown.setCurrentIndex(self.dictionarySizes.index(self.dictionarySize)) self.dictionarySizeDropDown.currentIndexChanged.connect(self.dictionarySizeChanged) self.nmfControlsLayout.addWidget(self.dictionarySizeDropDown) self.nmfControlsLayout.addStretch(1) self.nmfControlsLayout.addWidget(QtGui.QLabel('Num Updates:')) self.numHUpdatesSpinBox = QtGui.QSpinBox() self.nmfControlsLayout.addWidget(self.numHUpdatesSpinBox) self.nmfControlsLayout.addStretch(1) def initLocalizationControls(self): self.localizationControlsLayout = QtGui.QHBoxLayout() self.localizationControlsLayout.addStretch(3) self.localizationCheckBox = QtGui.QCheckBox('Enable Localization') self.localizationCheckBox.setChecked(self.localizationEnabled) self.localizationCheckBox.stateChanged.connect(self.localizationStateChanged) self.localizationControlsLayout.addWidget(self.localizationCheckBox) self.localizationControlsLayout.addStretch(1) self.localizationWindowSizeLabel = QtGui.QLabel('Sliding Window Size:') self.localizationControlsLayout.addWidget(self.localizationWindowSizeLabel) self.localziaitonWindowSizeSpinBox = QtGui.QSpinBox() self.localziaitonWindowSizeSpinBox.setMinimum(1) self.localziaitonWindowSizeSpinBox.setMaximum(128) self.localziaitonWindowSizeSpinBox.setValue(self.localizationWindowSize) self.localziaitonWindowSizeSpinBox.valueChanged.connect(self.localizationParamsChanged) self.localizationControlsLayout.addWidget(self.localziaitonWindowSizeSpinBox) self.localizationControlsLayout.addStretch(3) def initUIControls(self): self.uiConrolsWidget = QtGui.QWidget() buttonBarWidgetLayout = QtGui.QHBoxLayout(spacing=0) buttonBarWidgetLayout.setContentsMargins(0, 0, 0, 0) buttonBarWidgetLayout.setSpacing(0) self.uiConrolsWidget.setLayout(buttonBarWidgetLayout) def addButton(label, widget=None, function=None): button = QtGui.QPushButton(label) if function is None: button.clicked.connect(lambda: widget.setVisible(widget.isHidden())) else: button.clicked.connect(function) button.setStyleSheet('QPushButton {' 'border-color: black;' 'border-width: 5px;}') buttonBarWidgetLayout.addWidget(button) return button addButton('Info', function=self.toggleInfoViews) self.toggleSeparationButton = addButton(self.separationOnIconString, function=self.toggleSeparation) self.playPauseButton = addButton(self.playIconString, function=self.togglePlay) def initVisualizationWidgets(self): self.inputSpectrogramWidget = self.createGraphicsLayoutWidget(self.backgroundColor) inputSpectrogramViewBox = self.inputSpectrogramWidget.addViewBox() self.inputSpectrogramHistoryImageItem = pg.ImageItem(self.inputSpectrogramHistory.values) # , border=self.borderColor) inputSpectrogramViewBox.addItem(self.inputSpectrogramHistoryImageItem) inputSpectrogramViewBox.setRange(xRange=(0, self.inputSpectrogramHistory.values.shape[1]), yRange=(0, self.inputSpectrogramHistory.values.shape[0]), padding=0) self.outputSpectrogramWidget = self.createGraphicsLayoutWidget(self.backgroundColor) outputSpectrogramViewBox = self.outputSpectrogramWidget.addViewBox() self.outputSpectrogramHistoryImageItem = pg.ImageItem(self.outputSpectrogramHistory.values) # , border=self.borderColor) outputSpectrogramViewBox.addItem(self.outputSpectrogramHistoryImageItem) outputSpectrogramViewBox.setRange(xRange=(0, self.outputSpectrogramHistory.values.shape[1] - 1), yRange=(0, self.outputSpectrogramHistory.values.shape[0] - 1), padding=0) self.gccPHATHistoryWidget = self.createGraphicsLayoutWidget(self.backgroundColor) gccPHATHistoryViewBox = self.gccPHATHistoryWidget.addViewBox() # invertY=True) self.gccPHATImageItem = pg.ImageItem(self.gccPHATHistory.values) # , border=self.borderColor) gccPHATHistoryViewBox.addItem(self.gccPHATImageItem) gccPHATHistoryViewBox.setRange(xRange=(0, self.gccPHATHistory.values.shape[1] - 1), yRange=(0, self.gccPHATHistory.values.shape[0] - 1), padding=0) self.tdoaPlotDataItem = pg.PlotDataItem( pen=pg.mkPen((255, 0, 0, 255), width=4) ) gccPHATHistoryViewBox.addItem(self.tdoaPlotDataItem) dictionarySize = self.dictionarySizes[self.dictionarySizeDropDown.currentIndex()] self.coefficientMaskWidget = self.createGraphicsLayoutWidget(self.backgroundColor) self.coefficientMaskViewBox = self.coefficientMaskWidget.addViewBox() self.coefficientMaskHistory = self.coefficientMaskHistories[dictionarySize] self.coefficientMaskHistoryImageItem = pg.ImageItem() # , border=self.borderColor) self.coefficientMaskViewBox.addItem(self.coefficientMaskHistoryImageItem) self.dictionaryWidget = self.createGraphicsLayoutWidget(self.backgroundColor) self.dictionaryViewBox = self.dictionaryWidget.addViewBox() self.dictionaryImageItem = pg.ImageItem() # 1 - visualizedDictionary)#, border=self.borderColor) self.dictionaryViewBox.addItem(self.dictionaryImageItem) self.dictionarySizeChanged(False) def addSeparator(self, layout, lineStyle=QtGui.QFrame.HLine): separator = QtGui.QFrame() separator.setFrameShape(lineStyle) separator.setFrameShadow(QtGui.QFrame.Sunken) layout.addWidget(separator) def createGraphicsLayoutWidget(self, backgroundColor, border=None, contentMargins=(0, 0, 0, 0)): graphicsLayoutWidget = pg.GraphicsLayoutWidget(border=border) graphicsLayoutWidget.setBackground(backgroundColor) graphicsLayoutWidget.ci.layout.setContentsMargins(*contentMargins) graphicsLayoutWidget.ci.layout.setSpacing(0) return graphicsLayoutWidget def updateGCCPHATPlot(self): gccPHATValues = np.squeeze(np.mean(self.gccPHATHistory.values, axis=-1)) gccPHATValues -= min(gccPHATValues) gccPHATValues /= max(gccPHATValues) self.gccPHATPlot.setData(y=gccPHATValues) if self.rollingImages: self.gccPHATImageItem.setImage(-self.gccPHATHistory.getUnraveledArray().T) self.tdoaPlotDataItem.setData(y=self.tdoaHistory.getUnraveledArray()[0]) self.inputSpectrogramHistoryImageItem.setImage(self.inputSpectrogramHistory.getUnraveledArray().T) self.outputSpectrogramHistoryImageItem.setImage(self.outputSpectrogramHistory.getUnraveledArray().T) self.coefficientMaskHistoryImageItem.setImage(self.coefficientMaskHistory.getUnraveledArray().T, levels=[0, 1]) else: self.gccPHATImageItem.setImage(-self.gccPHATHistory.values.T) self.tdoaPlotDataItem.setData(y=self.tdoaHistory.values[0]) self.inputSpectrogramHistoryImageItem.setImage(self.inputSpectrogramHistory.values.T) self.outputSpectrogramHistoryImageItem.setImage(self.outputSpectrogramHistory.values.T) self.coefficientMaskHistoryImageItem.setImage(self.coefficientMaskHistory.values.T, levels=[0, 1]) if self.localizationCheckBox.isChecked(): sliderValue = self.tdoaHistory.get()[0] / (self.numTDOAs-1) * 100 self.targetModeWindowTDOASlider.setValue(sliderValue) def toggleInfoViews(self): isHidden = self.infoLabelWidgets[0].isHidden() for view in self.infoLabelWidgets: view.setVisible(isHidden) #map(lambda view: view.setVisible(isHidden), self.infoLabelWidgets) def togglePlay(self): playing = self.playPauseButton.text() == self.playIconString logging.info('GCCNMFInterface: setting playing: %s' % playing) self.playPauseButton.setText(self.pauseIconString if playing else self.playIconString) if playing: QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.tdoaRegionChanged() self.updateTogglePlayParamsGCCNMFProcess() self.updateTogglePlayParamsAudioProcess(playing) QtGui.QApplication.restoreOverrideCursor() else: self.updateTogglePlayParamsAudioProcess(playing) self.gccPHATPlotTimer.start(100) if playing else self.gccPHATPlotTimer.stop() def toggleSeparation(self): separationEnabled = self.toggleSeparationButton.text() == self.separationOffIconString logging.info('GCCNMFInterface: toggleSeparation(): now %s' % separationEnabled) self.toggleSeparationButton.setText(self.separationOnIconString if separationEnabled else self.separationOffIconString) self.queueParams(self.toggleSeparationGCCNMFProcessQueue, self.toggleSeparationGCCNMFProcessAck, {'separationEnabled': separationEnabled}, 'separationEnabledParameters') def numHUpdatesChanged(self): numHUpdates = int(self.numHUpdatesTextBox.text()) logging.info('GCCNMFInterface: setting numHUpdates: %d' % numHUpdates) self.queueParams(self.togglePlayGCCNMFProcessQueue, self.togglePlayGCCNMFProcessAck, {'numHUpdates': numHUpdates}, 'gccNMFProcessTogglePlayParameters') def updateFileNameAudioProcess(self): self.queueParams(self.togglePlayAudioProcessQueue, self.togglePlayAudioProcessAck, {'fileName': self.selectedFilePath}, 'audioProcessParameters') def updateTogglePlayParamsAudioProcess(self, playing): self.queueParams(self.togglePlayAudioProcessQueue, self.togglePlayAudioProcessAck, {'fileName': self.audioFilePaths[self.selectedFileIndex], 'start' if playing else 'stop': ''}, 'audioProcessParameters') def updateTogglePlayParamsGCCNMFProcess(self): self.queueParams(self.togglePlayGCCNMFProcessQueue, self.togglePlayGCCNMFProcessAck, {'numTDOAs': self.numTDOAs, 'dictionarySize': int(self.dictionarySizeDropDown.currentText())}, 'gccNMFProcessTogglePlayParameters') def tdoaRegionChanged(self): self.queueParams(self.tdoaParamsGCCNMFProcessQueue, self.tdoaParamsGCCNMFProcessAck, {'targetTDOAIndex': self.targetWindowFunctionPlot.getTDOA(), 'targetTDOAEpsilon': self.targetWindowFunctionPlot.getWindowWidth(), # targetTDOAEpsilon, 'targetTDOABeta': self.targetWindowFunctionPlot.getBeta(), 'targetTDOANoiseFloor': self.targetWindowFunctionPlot.getNoiseFloor()}, 'gccNMFProcessTDOAParameters (region)') self.targetWindowFunctionPlot.updateData() def localizationParamsChanged(self): self.queueParams(self.tdoaParamsGCCNMFProcessQueue, self.tdoaParamsGCCNMFProcessAck, {'localizationEnabled': self.localizationCheckBox.isChecked(), 'localizationWindowSize': int(self.localziaitonWindowSizeSpinBox.value())}, 'gccNMFProcessTDOAParameters (localization)') def dictionarySizeChanged(self, changeGCCNMFProcessor=True): self.dictionarySize = self.dictionarySizes[self.dictionarySizeDropDown.currentIndex()] logging.info('GCCNMFInterface: setting dictionarySize: %d' % self.dictionarySize) visualizedDictionary = self.dictionariesW[self.dictionaryType][self.dictionarySize] self.dictionaryImageItem.setImage(visualizedDictionary) self.dictionaryViewBox.setXRange(0, visualizedDictionary.shape[0] - 1, padding=0) self.dictionaryViewBox.setYRange(0, visualizedDictionary.shape[1] - 1, padding=0) self.coefficientMaskHistory = self.coefficientMaskHistories[self.dictionarySize] self.coefficientMaskViewBox.setXRange(0, self.coefficientMaskHistory.values.shape[1] - 1, padding=0) self.coefficientMaskViewBox.setYRange(0, self.coefficientMaskHistory.values.shape[0] - 1, padding=0) if changeGCCNMFProcessor: self.queueParams(self.togglePlayGCCNMFProcessQueue, self.togglePlayGCCNMFProcessAck, {'dictionarySize': self.dictionarySize}, 'gccNMFProcessTogglePlayParameters') def dictionaryTypeChanged(self): dictionaryType = self.dictionaryTypes[self.dictionaryTypeDropDown.currentIndex()] logging.info('GCCNMFInterface: setting dictionarySize: %s' % dictionaryType) self.queueParams(self.togglePlayGCCNMFProcessQueue, self.togglePlayGCCNMFProcessAck, {'dictionaryType': dictionaryType}, 'gccNMFProcessTogglePlayParameters') def localizationStateChanged(self): onlineLocalizationEnabled = self.localizationCheckBox.isChecked() self.targetModeWindowTDOASlider.setEnabled(not onlineLocalizationEnabled) self.targetModeWindowTDOALabel.setEnabled(not onlineLocalizationEnabled) self.localziaitonWindowSizeSpinBox.setEnabled(onlineLocalizationEnabled) self.localizationWindowSizeLabel.setEnabled(onlineLocalizationEnabled) self.localizationParamsChanged() def queueParams(self, queue, ack, params, label='params'): ack.clear() logging.debug('GCCNMFInterface: putting %s' % label) queue.put(params) logging.debug('GCCNMFInterface: put %s' % label) ack.wait() logging.debug('GCCNMFInterface: ack received') def generalizedGaussian(x, alpha, beta, mu): return np.exp( - (np.abs(x-mu) / alpha) ** beta ) class TargetWindowFunctionPlot(pg.PlotDataItem): def __init__(self, tdoaRegionItem, targetModeWindowTDOASlider, targetModeWindowBetaSlider, targetModeWindowNoiseFloorSlider, targetModeWindowWidthSlider, numTDOAs, *args, **kwargs): super(TargetWindowFunctionPlot, self).__init__(*args, **kwargs) self.tdoaRegionItem = tdoaRegionItem self.targetModeWindowTDOASlider = targetModeWindowTDOASlider self.targetModeWindowBetaSlider = targetModeWindowBetaSlider self.targetModeWindowNoiseFloorSlider = targetModeWindowNoiseFloorSlider self.targetModeWindowWidthSlider = targetModeWindowWidthSlider self.targetModeWindowTDOASlider.valueChanged.connect(self.updateData) self.targetModeWindowBetaSlider.valueChanged.connect(self.updateData) self.targetModeWindowNoiseFloorSlider.valueChanged.connect(self.updateData) self.targetModeWindowWidthSlider.valueChanged.connect(self.updateData) self.numTDOAs = numTDOAs self.tdoas = np.arange(self.numTDOAs).astype(np.float32) def updateData(self): mu = self.getTDOA() alpha = self.getWindowWidth() beta = self.getBeta() noiseFloor = self.getNoiseFloor() data = generalizedGaussian(self.tdoas, alpha, beta, mu) data -= min(data) data = data / max(data) * (1 - noiseFloor) + noiseFloor self.setData(self.tdoas, data) def getBeta(self): lnBeta = self.targetModeWindowBetaSlider.value() / 100.0 lnBeta *= 10.0 lnBeta -= 5.0 beta = np.exp(lnBeta) return beta def getNoiseFloor(self): noiseFloorValue = self.targetModeWindowNoiseFloorSlider.value() / 100.0 return noiseFloorValue def getWindowWidth(self): windowWidth = self.targetModeWindowWidthSlider.value() / 100.0 * self.numTDOAs return windowWidth def getTDOA(self): tdoa = self.targetModeWindowTDOASlider.value() / 100.0 * self.numTDOAs return tdoa def getVisualizedDictionariesW(dictionariesW): visualizedDictionariesW = OrderedDict() for dictionaryType, dictionaries in dictionariesW.items(): currentDictionaries = OrderedDict() for dictionarySize, dictionary in dictionaries.items(): visualizedDictionary = dictionary.copy() visualizedDictionary /= np.max(visualizedDictionary) visualizedDictionary **= (1 / 3.0) visualizedDictionary = 1 - visualizedDictionary currentDictionaries[dictionarySize] = visualizedDictionary visualizedDictionariesW[dictionaryType] = currentDictionaries return visualizedDictionariesW