Skip to content

Commit

Permalink
merging speakercalibration changes to master
Browse files Browse the repository at this point in the history
ter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
  • Loading branch information
alakunina committed Sep 19, 2017
2 parents 0cb98c8 + e647858 commit a8adffd
Showing 1 changed file with 202 additions and 40 deletions.
242 changes: 202 additions & 40 deletions plugins/speakercalibration.py
Expand Up @@ -38,7 +38,9 @@
AMPLITUDE_STEP = 0.0005
MAX_AMPLITUDE = 0.5

DEFAULT_INTENSITY = 50 # dB-SPL
DEFAULT_INTENSITY = 50 # intensity used for tone and chord calibration (dB-SPL)
DEFAULT_POWER_RMS = 60 # RMS power in time domain (dB-SPL)
DEFAULT_POWER_NARROWBAND = 40 # average power of narrowband sound (dB-SPL)

DATADIR = '/var/tmp/'

Expand All @@ -65,21 +67,23 @@ def create_sound(soundParams):
soundObjList = []
for indcomp in range(nTones):
soundObjList.append(pyo.Sine(freq=freqEachComp[indcomp],mul=amplitude))
if soundParams['type']=='noise':
soundObjList = [pyo.Noise(mul=amplitude)]
return soundObjList

class OutputButton(QtGui.QPushButton):
'''Single button for manual output'''
def __init__(self, soundServer, soundFreq, channel=1, parent=None):
super(OutputButton, self).__init__(str(int(np.round(soundFreq))), parent)
def __init__(self, soundServer, title, soundType='sine',channel=1, parent=None):
super(OutputButton, self).__init__(title, parent)

self.soundServer = soundServer
self.soundFreq = soundFreq
self.soundTitle = title
self.soundAmplitude = DEFAULT_AMPLITUDE
self.channel = channel
self.soundType = 'sine'
self.soundType = soundType
self.setCheckable(True)
self.clicked.connect(self.toggleOutput)
self.create_sound(soundType='sine')
self.create_sound(soundType=soundType)
'''
self.soundObj = pyo.Sine(freq=self.soundFreq,mul=DEFAULT_AMPLITUDE)
if soundFreq<40000:
Expand All @@ -89,11 +93,13 @@ def __init__(self, soundServer, soundFreq, channel=1, parent=None):
'''
def create_sound(self,soundType):
if soundType=='sine':
soundParams = {'type':'sine', 'frequency':self.soundFreq,
soundParams = {'type':'sine', 'frequency':int(self.soundTitle),
'amplitude':self.soundAmplitude}
elif soundType=='chord':
soundParams = {'type':'chord', 'frequency':self.soundFreq, 'ntones':12, 'factor':1.2,
soundParams = {'type':'chord', 'frequency':int(self.soundTitle), 'ntones':12, 'factor':1.2,
'amplitude':self.soundAmplitude}
elif soundType=='noise':
soundParams = {'type':'noise', 'amplitude':self.soundAmplitude}
self.soundObjList = create_sound(soundParams)

def toggleOutput(self):
Expand Down Expand Up @@ -144,9 +150,9 @@ def __init__(self,soundButton,parent=None):
def change_amplitude(self,value):
self.soundButton.change_amplitude(value)

class SoundControl(QtGui.QGroupBox):
class SoundControlGUI(QtGui.QGroupBox):
def __init__(self, soundServer, channel=0, channelName='left', parent=None):
super(SoundControl, self).__init__(parent)
super(SoundControlGUI, self).__init__(parent)
self.soundServer = soundServer
self.soundFreqs = SOUND_FREQUENCIES
# -- Create graphical objects --
Expand All @@ -164,7 +170,7 @@ def __init__(self, soundServer, channel=0, channelName='left', parent=None):
playAllButton.clicked.connect(self.play_all)

for indf,onefreq in enumerate(self.soundFreqs):
self.outputButtons[indf] = OutputButton(self.soundServer,onefreq,
self.outputButtons[indf] = OutputButton(self.soundServer,str(int(np.round(onefreq))),
channel=self.channel)
self.amplitudeControl[indf] = AmplitudeControl(self.outputButtons[indf])
layout.addWidget(self.outputButtons[indf], indf+1, 0)
Expand All @@ -186,6 +192,35 @@ def amplitude_array(self):
for indf,oneAmplitude in enumerate(self.amplitudeControl):
amplitudeEach[indf] = oneAmplitude.value()
return amplitudeEach

class NoiseSoundControlGUI(QtGui.QGroupBox):
def __init__(self, soundServer, channel=0, channelName='left', parent=None):
super(NoiseSoundControlGUI, self).__init__(parent)
self.soundServer = soundServer
self.channel=channel

# -- Create graphical objects --
layout = QtGui.QGridLayout()
self.outputButtons = []
self.amplitudeControl=[]

self.outputButtons.append(OutputButton(self.soundServer, 'RMS Power', soundType='noise', channel=self.channel))
self.outputButtons.append(OutputButton(self.soundServer, 'Narrowband Power', soundType='noise', channel=self.channel))

for indButton, outputButton in enumerate(self.outputButtons):
self.amplitudeControl.append(AmplitudeControl(outputButton))
layout.addWidget(self.outputButtons[indButton], indButton+1, 0)
layout.addWidget(self.amplitudeControl[indButton], indButton+1, 1)

self.setLayout(layout)
self.setTitle('Speaker '+channelName)

# If multiple amplitude controls
def amplitude_array(self):
amplitudeEach = np.empty(len(self.amplitudeControl))
for indf,oneAmplitude in enumerate(self.amplitudeControl):
amplitudeEach[indf] = oneAmplitude.value()
return amplitudeEach

class LoadButton(QtGui.QPushButton):
'''
Expand Down Expand Up @@ -251,12 +286,13 @@ def save_data(self, date=None, filename=None):
else:
if date is None:
date = time.strftime('%Y%m%d%H%M%S',time.localtime())
soundType = self.soundControlArray[0].outputButtons[0].soundType
dataRootDir = self.datadir
fileExt = 'h5'
dataDir = dataRootDir #os.path.join(dataRootDir)
if not os.path.exists(dataDir):
os.makedirs(dataDir)
fileNameOnly = 'speaker_calibration_{0}.{1}'.format(date,fileExt)
fileNameOnly = 'speaker_calibration_{0}_{1}.{2}'.format(soundType,date,fileExt)
defaultFileName = os.path.join(dataDir,fileNameOnly)

self.logMessage.emit('Saving data...')
Expand Down Expand Up @@ -284,16 +320,31 @@ def save_data(self, date=None, filename=None):
h5file = h5py.File(fname,'w')

try:
dsetAmp = h5file.create_dataset('amplitude',data=amplitudeData)
dsetAmp.attrs['Channels'] = 'left,right' # FIXME: hardcoded
dsetAmp.attrs['Units'] = '(none)' # FIXME: hardcoded
dsetFreq = h5file.create_dataset('frequency',data=SOUND_FREQUENCIES)
dsetFreq.attrs['Units'] = 'Hz' # FIXME: hardcoded
dsetRef = h5file.create_dataset('intensity',data=DEFAULT_INTENSITY)
dsetRef.attrs['Units'] = 'dB-SPL' # FIXME: hardcoded
dsetRef = h5file.create_dataset('computerSoundLevel',
data=rigsettings.SOUND_VOLUME_LEVEL)
dsetRef.attrs['Units'] = '%' # FIXME: hardcoded
if soundType=='noise':
dsetAmp = h5file.create_dataset('amplitudeRMS',data=amplitudeData[:,0]) # FIXME: hardcoded method of separating amplitudes
dsetAmp.attrs['Channels'] = 'left,right' # FIXME: hardcoded
dsetAmp.attrs['Units'] = '(none)' # FIXME: hardcoded
dsetAmp = h5file.create_dataset('amplitudeNarrowband',data=amplitudeData[:,1])
dsetAmp.attrs['Channels'] = 'left,right' # FIXME: hardcoded
dsetAmp.attrs['Units'] = '(none)' # FIXME: hardcoded
dsetRef = h5file.create_dataset('powerRMS',data=DEFAULT_POWER_RMS)
dsetRef.attrs['Units'] = 'dB-SPL' # FIXME: hardcoded
dsetRef = h5file.create_dataset('powerNarrowband',data=DEFAULT_POWER_NARROWBAND)
dsetRef.attrs['Units'] = 'dB-SPL' # FIXME: hardcoded
dsetRef = h5file.create_dataset('computerSoundLevel',
data=rigsettings.SOUND_VOLUME_LEVEL)
dsetRef.attrs['Units'] = '%' # FIXME: hardcoded
else:
dsetAmp = h5file.create_dataset('amplitude',data=amplitudeData)
dsetAmp.attrs['Channels'] = 'left,right' # FIXME: hardcoded
dsetAmp.attrs['Units'] = '(none)' # FIXME: hardcoded
dsetFreq = h5file.create_dataset('frequency',data=SOUND_FREQUENCIES)
dsetFreq.attrs['Units'] = 'Hz' # FIXME: hardcoded
dsetRef = h5file.create_dataset('intensity',data=DEFAULT_INTENSITY)
dsetRef.attrs['Units'] = 'dB-SPL' # FIXME: hardcoded
dsetRef = h5file.create_dataset('computerSoundLevel',
data=rigsettings.SOUND_VOLUME_LEVEL)
dsetRef.attrs['Units'] = '%' # FIXME: hardcoded
except UserWarning as uwarn:
self.logMessage.emit(uwarn.message)
print uwarn.message
Expand All @@ -314,9 +365,9 @@ def __init__(self,parent=None):
QtGui.QSizePolicy.Expanding)


class SpeakerCalibration(QtGui.QMainWindow):
class SpeakerCalibrationGUI(QtGui.QMainWindow):
def __init__(self, parent=None, paramfile=None, paramdictname=None):
super(SpeakerCalibration, self).__init__(parent)
super(SpeakerCalibrationGUI, self).__init__(parent)

self.name = 'speakercalibration'
self.soundServer = self.initialize_sound()
Expand All @@ -326,8 +377,8 @@ def __init__(self, parent=None, paramfile=None, paramdictname=None):
layoutMain = QtGui.QHBoxLayout()
layoutRight = QtGui.QVBoxLayout()

self.soundControlL = SoundControl(self.soundServer, channel=0, channelName='left')
self.soundControlR = SoundControl(self.soundServer, channel=1, channelName='right')
self.soundControlL = SoundControlGUI(self.soundServer, channel=0, channelName='left')
self.soundControlR = SoundControlGUI(self.soundServer, channel=1, channelName='right')

self.saveButton = SaveButton([self.soundControlL,self.soundControlR])
soundTypeLabel = QtGui.QLabel('Sound type')
Expand All @@ -338,7 +389,7 @@ def __init__(self, parent=None, paramfile=None, paramdictname=None):
soundTargetIntensityLabel = QtGui.QLabel('Target intensity [dB-SPL]')
self.soundTargetIntensity = QtGui.QLineEdit()
self.soundTargetIntensity.setText(str(DEFAULT_INTENSITY))
self.soundTargetIntensity.setEnabled(False)
#self.soundTargetIntensity.setEnabled(False)
computerSoundLevelLabel = QtGui.QLabel('Computer sound level [%]')
self.computerSoundLevel = QtGui.QLineEdit()
self.computerSoundLevel.setText(str(rigsettings.SOUND_VOLUME_LEVEL))
Expand Down Expand Up @@ -384,7 +435,7 @@ def __init__(self, parent=None, paramfile=None, paramdictname=None):

# -- Connect other signals --
#self.saveData.buttonSaveData.clicked.connect(self.save_to_file)

def change_sound_type(self,soundTypeInd):
for oneOutputButton in self.soundControlL.outputButtons:
#oneOutputButton.create_sound(self.soundTypeList[soundTypeInd])
Expand Down Expand Up @@ -419,6 +470,110 @@ def closeEvent(self, event):
self.soundServer.shutdown()
#self.pyoServer.shutdown()
event.accept()

class NoiseSpeakerCalibrationGUI(QtGui.QMainWindow):
def __init__(self, parent=None, paramfile=None, paramdictname=None):
super(NoiseSpeakerCalibrationGUI, self).__init__(parent)

self.name = 'noisespeakercalibration'
self.soundServer = self.initialize_sound()

# -- Add graphical widgets to main window --
self.centralWidget = QtGui.QWidget()
layoutMain = QtGui.QHBoxLayout()
layoutRight = QtGui.QVBoxLayout()

self.soundControlL = NoiseSoundControlGUI(self.soundServer, channel=0, channelName='left')
self.soundControlR = NoiseSoundControlGUI(self.soundServer, channel=1, channelName='right')
for oneOutputButton in self.soundControlL.outputButtons:
oneOutputButton.soundType = 'noise'
for oneOutputButton in self.soundControlR.outputButtons:
oneOutputButton.soundType = 'noise'

self.saveButton = SaveButton([self.soundControlL,self.soundControlR])

noiseTargetIntensityLabel = QtGui.QLabel('Target RMS power in time domain [dB-SPL]')
self.noiseTargetIntensity = QtGui.QLineEdit()
self.noiseTargetIntensity.setText(str(DEFAULT_POWER_RMS))
#self.noiseTargetIntensity.setEnabled(False)
powerTargetIntensityLabel = QtGui.QLabel('Target power at specific frequency [dB-SPL]')
self.powerTargetIntensity = QtGui.QLineEdit()
self.powerTargetIntensity.setText(str(DEFAULT_POWER_NARROWBAND))
#self.powerTargetIntensity.setEnabled(False)
computerSoundLevelLabel = QtGui.QLabel('Computer sound level [%]')
self.computerSoundLevel = QtGui.QLineEdit()
self.computerSoundLevel.setText(str(rigsettings.SOUND_VOLUME_LEVEL))
self.computerSoundLevel.setEnabled(False)

#TODO: Implement loading, probably not plotting though
# self.loadButton = LoadButton([self.soundControlL,self.soundControlR])
# self.plotButton = PlotButton([self.soundControlL,self.soundControlR])

layoutRight.addWidget(self.saveButton)

layoutRight.addWidget(noiseTargetIntensityLabel)
layoutRight.addWidget(self.noiseTargetIntensity)
layoutRight.addWidget(powerTargetIntensityLabel)
layoutRight.addWidget(self.powerTargetIntensity)
layoutRight.addWidget(computerSoundLevelLabel)
layoutRight.addWidget(self.computerSoundLevel)

# layoutRight.addWidget(self.loadButton)
# layoutRight.addWidget(self.plotButton)
layoutRight.addStretch()

layoutMain.addWidget(self.soundControlL)
layoutMain.addWidget(VerticalLine())
layoutMain.addWidget(self.soundControlR)
layoutMain.addWidget(VerticalLine())
layoutMain.addLayout(layoutRight)


self.centralWidget.setLayout(layoutMain)
self.setCentralWidget(self.centralWidget)

# -- Center in screen --
self._center_in_screen()

# -- Add variables storing results --
#self.results = arraycontainer.Container()

# -- Connect messenger --
self.messagebar = messenger.Messenger()
self.messagebar.timedMessage.connect(self._show_message)
self.messagebar.collect('Created window')

# -- Connect signals to messenger
#TODO: enable saving and uncomment below
self.saveButton.logMessage.connect(self.messagebar.collect)

def initialize_sound(self):
s = pyo.Server(audio='jack').boot()
#s = pyo.Server().boot()
s.start()
return s

def _show_message(self,msg):
self.statusBar().showMessage(str(msg))
print msg

def _center_in_screen(self):
qr = self.frameGeometry()
cp = QtGui.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())

def closeEvent(self, event):
'''
Executed when closing the main window.
This method is inherited from QtGui.QMainWindow, which explains
its camelCase naming.
'''
#print 'ENTERED closeEvent()' # DEBUG
#print 'Closing all connections.' # DEBUG
self.soundServer.shutdown()
#self.pyoServer.shutdown()
event.accept()

class Calibration(object):
'''
Expand Down Expand Up @@ -464,15 +619,17 @@ class NoiseCalibration(object):
def __init__(self,filename=None):
if filename is not None:
h5file = h5py.File(filename,'r')
self.amplitude = h5file['amplitude'][...]
self.intensity = h5file['intensity'][...]
self.power = h5file['power'][...]
self.amplitudeRMS = h5file['amplitudeRMS'][...]
self.amplitudeNarrowband = h5file['amplitudeNarrowband'][...]
self.powerRMS = h5file['powerRMS'][...]
self.powerNarrowband = h5file['powerNarrowband'][...]
h5file.close()
else:
self.amplitude = 0.1*np.ones((2,2))
self.intensity = 60
self.power = 40
self.nChannels = self.amplitude.shape[0]
self.amplitudeRMS = 0.1*np.ones(2)
self.amplitudeNarrowband = 0.1*np.ones(2)
self.powerRMS = 60
self.powerNarrowband = 40
self.nChannels = self.amplitudeRMS.shape[0]

def find_amplitude(self, intensity, type='rms'):
'''
Expand All @@ -482,11 +639,11 @@ def find_amplitude(self, intensity, type='rms'):
Returns an array with the amplitude for each channel.
'''
if type == 'rms':
ampAtRef = self.amplitude[:,0]
dBdiff = intensity-self.intensity
ampAtRef = self.amplitudeRMS
dBdiff = intensity-self.powerRMS
elif type == 'narrowband':
ampAtRef = self.amplitude[:,1]
dBdiff = intensity-self.power
ampAtRef = self.amplitudeNarrowband
dBdiff = intensity-self.powerNarrowband
ampFactor = 10**(dBdiff/20.0)
return np.array(ampAtRef)*ampFactor

Expand All @@ -496,7 +653,12 @@ def find_amplitude(self, intensity, type='rms'):
app=QtGui.QApplication.instance() # checks if QApplication already exists
if not app: # create QApplication if it doesnt exist
app = QtGui.QApplication(sys.argv)
spkcal = SpeakerCalibration()
args = sys.argv[1:]
if len(args):
if args[0]=='noise':
spkcal = NoiseSpeakerCalibrationGUI()
else:
spkcal = SpeakerCalibrationGUI()
spkcal.show()
sys.exit(app.exec_())
'''
Expand Down

0 comments on commit a8adffd

Please sign in to comment.