Example #1
0
 def initAUD(self):
     #
     info = QAudioDeviceInfo.defaultInputDevice()
     if (~info.isFormatSupported(self.audio.format)):
         # print("警告,设置的默认音频格式并不支持,将尝试采用最相近的支持格式")
         # 不知道这里面有什么神改动?
         self.audio.format  = info.nearestFormat(self.audio.format)
     #
     update_interval = 160
     self.audioRecorder = QAudioInput(self.audio.format)
     self.audioRecorder.setNotifyInterval(update_interval) #按毫秒ms 类似于QTimer的作用
     self.audioRecorder.notify.connect(self.processAudioData)
     self.audioRecorder_TD = QThread()
     self.audioRecorder.moveToThread(self.audioRecorder_TD)
     self.audioRecorder_TD.started.connect(self.startRecord)
     self.audioRecorder.stateChanged.connect(self.recordStopped)
     # 总结来说线程只是一个容器,里面执行的循环要是没法结束,强制退出也不好操作
     # 所以还是好好写好任务流然后发送信号比较合理
     self.audioPlayer = QAudioOutput(self.audio.format)
     self.audioPlayer.setNotifyInterval(update_interval)
     self.audioPlayer.notify.connect(self.processAudioData)
     self.audioPlayer_TD = QThread()
     self.audioPlayer.moveToThread(self.audioPlayer_TD)
     self.audioPlayer_TD.started.connect(self.startPlay)
     self.audioPlayer.stateChanged.connect(self.playStopped)
Example #2
0
    def in_dev_change(self, new_index):

        # Disconnect and stop the devices if they are connected.
        self.disconnect_devices()

        self.input_device = None  # device object goes out of scope

        # Get the QAudioDeviceInfo corresponding to this index of the combox.
        audio_info = self.input_info_list[new_index]

        # Create a new QAudioInput based on that.
        preferred_format = audio_info.preferredFormat()
        self.input_device = QAudioInput(audio_info, preferred_format)

        # the input device volume is always 1.0, wide open.
        self.input_device.setVolume(1.0)

        # The choice of buffer size has a major impact on the lag. It needs
        # to be small or there is severe echo; but if it is too small, there
        # is a sputtering or "motor-boating" effect.
        self.input_device.setBufferSize(384)

        # hook up possible debug status display
        self.input_device.stateChanged.connect(self.in_dev_state_change)

        # reconnect the devices if possible.

        self.reconnect_devices()
Example #3
0
    def __init__(self, output_path: str, mw: aqt.AnkiQt,
                 parent: QWidget) -> None:
        super().__init__(output_path)

        self.mw = mw
        self._parent = parent

        from PyQt5.QtMultimedia import QAudioDeviceInfo, QAudioFormat, QAudioInput

        format = QAudioFormat()
        format.setChannelCount(1)
        format.setSampleRate(44100)
        format.setSampleSize(16)
        format.setCodec("audio/pcm")
        format.setByteOrder(QAudioFormat.LittleEndian)
        format.setSampleType(QAudioFormat.SignedInt)

        device = QAudioDeviceInfo.defaultInputDevice()
        if not device.isFormatSupported(format):
            format = device.nearestFormat(format)
            print("format changed")
            print("channels", format.channelCount())
            print("rate", format.sampleRate())
            print("size", format.sampleSize())
        self._format = format

        self._audio_input = QAudioInput(device, format, parent)
Example #4
0
 def changeinput(self, val):
     audio = QAudioFormat()
     audio.setSampleRate(44100)
     audio.setSampleType(QAudioFormat.UnSignedInt)
     audio.setSampleSize(8)
     audio.setCodec('audio/pcm')
     audio.setChannelCount(1)
     self.input = QAudioInput(self.inputdevices[val], audio)
Example #5
0
 def setup(self):
     self.output.setFileName("record.pcm")
     self.output.open(QIODevice.WriteOnly | QIODevice.Truncate)
     settings = QAudioFormat()
     settings.setCodec("audio/pcm")
     settings.setSampleRate(16000)
     settings.setSampleSize(16)
     settings.setChannelCount(1)
     settings.setByteOrder(QAudioFormat.LittleEndian)
     settings.setSampleType(QAudioFormat.SignedInt)
     self.audio = QAudioInput(settings)
class AudioRecPlot(QWidget):

    def __init__(self):
        super().__init__()

        self.m_chart = QChart()

        chart_view = QChartView(self.m_chart)
        chart_view.setMinimumSize(800, 600)

        self.m_series = QLineSeries()
        self.m_chart.addSeries(self.m_series)

        axis_x = QValueAxis()
        axis_x.setRange(0, 2000)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Samples")

        axis_y = QValueAxis()
        axis_y.setRange(-1, 1)
        axis_y.setTitleText("Audio level")

        self.m_chart.setAxisX(axis_x, self.m_series)
        self.m_chart.setAxisY(axis_y, self.m_series)
        self.m_chart.setTitle("Data from the microphone")

        main_layout = QVBoxLayout()
        main_layout.addWidget(chart_view)
        self.setLayout(main_layout)

        format_audio = QAudioFormat()
        format_audio.setSampleRate(48000)
        format_audio.setChannelCount(1)
        format_audio.setSampleSize(8)
        format_audio.setCodec("audio/pcm")
        format_audio.setByteOrder(QAudioFormat.LittleEndian)
        format_audio.setSampleType(QAudioFormat.UnSignedInt)

        input_devices = QAudioDeviceInfo.defaultInputDevice()
        self.m_audio_input = QAudioInput(input_devices, format_audio)

        self.m_device = XYSeriesIODevice(self.m_series)
        self.m_device.open(QIODevice.WriteOnly)

        self.m_audio_input.start(self.m_device)

        self.init_ui()

    def init_ui(self):
        self.show()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.m_audio_input.stop()
        self.m_device.close()
Example #7
0
    def __init__(self):
        super(Recorder, self).__init__()
        self.setupUi(self)
        self.output = QFile()
        self.audio = QAudioInput()
        self.NEED_ASR = False
        self.Open = True

        self.th1 = threading.Thread(target=self.ASR)
        self.th1.start()

        self.Pause_Button.clicked.connect(self.toggle_pause)
        self.Record_Button.clicked.connect(self.toggle_record)
Example #8
0
class QDeckAudioItemWidget(QAudioInput):

    audio_input = None
    outputFile = None

    def __init__(self):
        super().__init__()

    def initAudioInput(self, filepath):

        self.outputFile = QFile()
        self.outputFile.setFileName(filepath)
        self.outputFile.open(QIODevice.WriteOnly | QIODevice.Truncate)

        format = QAudioFormat()
        format.setSampleType(QAudioFormat.Float)
        format.setSampleRate(44100)
        format.setChannelCount(1)
        format.setSampleSize(32)
        format.setCodec("audio/pcm")
        format.setByteOrder(QAudioFormat.LittleEndian)

        print(format.codec())

        #self.audio_input = QAudioInput(QAudioDeviceInfo.defaultInputDevice(), format);

        self.audio_input = QAudioInput(format)

        print(self.audio_input.error())
        print(self.audio_input.state())

        #QTimer.singleShot(3000, self,

    def start(self):
        self.audio_input.start(self.outputFile)

    def stop(self):
        self.audio_input.stop()
        self.outputFile.close()

    def suspend(self):
        self.audio_input.suspend()

    def resume(self):
        self.audio_input.resume()
Example #9
0
 def in_dev_change(self, new_index):
     if self.input_device:
         if self.otput_device:
             self.otput_device.stop()
         self.input_device.stop()
         self.input_device = None  # goodby object
     # Get the QAudioDeviceInfo corresponding to this index of the combox.
     audio_info = self.input_info_list[new_index]
     # Create a new QAudioInput based on that.
     preferred_format = audio_info.preferredFormat()
     self.input_device = QAudioInput(audio_info, preferred_format)
     self.input_device.setVolume(1.0)
     self.input_device.setBufferSize(384)
     # If we have an output device, redirect it to this input. This is
     # done by asking the input device for its QIODevice, and passing that
     # to the output device's start() method.
     if self.otput_device:
         self.input_device.start(self.otput_device.start())
 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
Example #11
0
    def initAudioInput(self, filepath):

        self.outputFile = QFile()
        self.outputFile.setFileName(filepath)
        self.outputFile.open(QIODevice.WriteOnly | QIODevice.Truncate)

        format = QAudioFormat()
        format.setSampleType(QAudioFormat.Float)
        format.setSampleRate(44100)
        format.setChannelCount(1)
        format.setSampleSize(32)
        format.setCodec("audio/pcm")
        format.setByteOrder(QAudioFormat.LittleEndian)

        print(format.codec())

        #self.audio_input = QAudioInput(QAudioDeviceInfo.defaultInputDevice(), format);

        self.audio_input = QAudioInput(format)

        print(self.audio_input.error())
        print(self.audio_input.state())
Example #12
0
   def on_actStart_triggered(self):
      audioFormat=QAudioFormat() #使用固定格式
      audioFormat.setSampleRate(8000)
      audioFormat.setChannelCount(1)
      audioFormat.setSampleSize(8)
      audioFormat.setCodec("audio/pcm")
      audioFormat.setByteOrder(QAudioFormat.LittleEndian)
      audioFormat.setSampleType(QAudioFormat.UnSignedInt)

      index=self.ui.comboDevices.currentIndex()
      deviceInfo =self.__deviceList[index]  #当前音频设备

      if (False== deviceInfo.isFormatSupported(audioFormat)):
         QMessageBox.critical(self,"错误","测试失败,输入设备不支持此设置")
         return

      self.audioDevice = QAudioInput(deviceInfo,audioFormat) #音频输入设备
      self.audioDevice.setBufferSize(self.BUFFER_SIZE)   #设置的缓冲区大小,字节数,并不一定等于实际数据块大小
      self.audioDevice.stateChanged.connect(self.do_stateChanged)  #状态变化


   ##1. 使用 start()->QIODevice 启动,返回的内置的IODevice, pull mode,利用readyRead()信号读出数据
      if self.ui.radioSaveMode_Inner.isChecked():
         self.ioDevice=self.audioDevice.start()  #返回内建的IODevice
         self.ioDevice.readyRead.connect(self.do_IO_readyRead)

   ## 2. 自定义流设备QWAudioBlockReader,push mode, start(QIODevice),不行
   ##      if self.ui.radioSaveMode_External.isChecked():
   ##         self.externalReader = QmyAudioReader()
   ##         self.externalReader.open(QIODevice.WriteOnly)
   ##         self.externalReader.updateBlockInfo.connect(self.do_updateBlockInfo)
   ##         self.audioDevice.start(self.externalReader)  #使用外建的IODevice
         
      
   ##3. 写入文件,用 start(QIODevice)启动
      if self.ui.radioSaveMode_QFile.isChecked():
         self.recordFile.setFileName("test.raw") 
         self.recordFile.open(QIODevice.WriteOnly)
         self.audioDevice.start(self.recordFile)  
Example #13
0
 def in_dev_change(self, new_index):
     if self.input_device:
         if self.otput_device:
             self.otput_device.stop()
         self.input_device.stop()
         self.input_device = None  # goodby object
     # Get the QAudioDeviceInfo corresponding to this index of the combox.
     audio_info = self.input_info_list[new_index]
     # Create a new QAudioInput based on that.
     preferred_format = audio_info.preferredFormat()
     self.input_device = QAudioInput(audio_info, preferred_format)
     self.input_device.setVolume(1.0)
     self.input_device.setBufferSize(384)
     # If we have an output device, redirect it to this input. This is
     # done by asking the input device for its QIODevice, and passing that
     # to the output device's start() method.
     if self.otput_device:
         self.input_device.start(self.otput_device.start())
Example #14
0
class SideToneWidget(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        # Save link to main window
        self.main_window = parent
        # Get the status bar
        self.status_bar = parent.statusBar()
        # Slot that will point to a QAudioInput some day
        self.input_device = None
        # Slot that will point to a QAudioOutput in time
        self.otput_device = None
        # set up layout, creating:
        # self.input_info_list, list of QAudioInfo for inputs
        # self.cb_inputs, combox of input names in same order
        # self.otput_info_list, list of QAudioInfo for outputs
        # self.cb_otputs, combox of output names in same order
        # self.volume, volume slider
        # self.mute, mute checkbox
        self._uic()
        # Connect up signals to slots.
        # Changes in the comboxes go to in_device and ot_device
        self.cb_inputs.currentIndexChanged.connect(self.in_dev_change)
        self.cb_otputs.currentIndexChanged.connect(self.ot_dev_change)
        # Mute button goes to mute_change
        self.mute.stateChanged.connect(self.mute_change)
        # Change in volume goes to volume_change
        self.volume.valueChanged.connect(self.volume_change)
        # Start with the mute switch on. This triggers the above two signals.
        self.mute.setChecked(True)

    # Slot for any change in volume (or mute). If we have an output device
    # then convert level to a real and pass to the output device. If the new
    # level is 0, tell the device to stop; if nonzero, tell it to start.
    # Note we don't do anything about the input device level, it is always 1.0
    def volume_change(self, new_level):
        if self.otput_device:  # we have an output device
            self.otput_device.setVolume(self.volume.value() / 100)
            if new_level == 0:  # looks like a mute
                # tell the output device to stop just in case it
                # doesn't know about volume control.
                self.otput_device.stop()
            else:  # non-zero level, if the output is stopped, start it
                if self.otput_device.state() == QAudio.StoppedState:
                    self.otput_device.start()

    # Slot for mute switch. Note that any change to the volume slider
    # generates a signal to the volume_change slot.
    def mute_change(self, onoff):
        if onoff:
            # Mute has been clicked ON. Remember the current volume.
            # Turn the volume to zero.
            self.volume_level = self.volume.value()
            self.volume.setValue(0)
        else:
            # Mute has been clicked OFF. If we do not yet have input and
            # output devices, get them. Then reset the old volume level.
            if self.otput_device is None:
                # We are starting up and have no devices. Fake a call to
                # the checkbox-change entries thus creating devices.
                self.in_dev_change(self.cb_inputs.currentIndex())
                self.ot_dev_change(self.cb_inputs.currentIndex())
            self.volume.setValue(self.volume_level)

    # Slots for changes in the selection of the input- and output-device
    # combo boxes. On startup we have neither an input nor an output device.
    # We do not know which combox the user will fiddle with first. So either
    # has to assume that the other device may not yet exist.
    #
    # On a change of input choice: if we have an input device, get rid of it.
    # Create a new input device. Set its level to 1.0. If we
    # have an output, connect the two.

    def in_dev_change(self, new_index):
        if self.input_device:
            if self.otput_device:
                self.otput_device.stop()
            self.input_device.stop()
            self.input_device = None  # goodby object
        # Get the QAudioDeviceInfo corresponding to this index of the combox.
        audio_info = self.input_info_list[new_index]
        # Create a new QAudioInput based on that.
        preferred_format = audio_info.preferredFormat()
        self.input_device = QAudioInput(audio_info, preferred_format)
        self.input_device.setVolume(1.0)
        self.input_device.setBufferSize(384)
        # If we have an output device, redirect it to this input. This is
        # done by asking the input device for its QIODevice, and passing that
        # to the output device's start() method.
        if self.otput_device:
            self.input_device.start(self.otput_device.start())
            # self.otput_device.start( self.input_device.start() )

    # On a change in the selection of output choice: If we have an output
    # device, get rid of it. Create a new output device. If we have an input
    # device, connect the two. Set the output level from the volume slider.

    def ot_dev_change(self, new_index):
        if self.otput_device:
            if self.input_device:
                self.input_device.stop()
            self.otput_device.stop()
            self.otput_device = None
        audio_info = self.otput_info_list[new_index]
        preferred_format = audio_info.preferredFormat()
        self.otput_device = QAudioOutput(audio_info, preferred_format)
        self.otput_device.setVolume(self.volume.value() / 100)
        # self.otput_device.setBufferSize( 384 )
        if self.input_device:
            self.input_device.start(self.otput_device.start())
            # self.otput_device.start( self.input_device.start() )

    def _uic(self):
        """
    set up our layout which consists of:

                 Big Honkin' Label
        [input combobox]    [output combobox]
               [volume slider]  [x] Mute

    hooking put the signals to useful slots is the job
    of __init__. Here just make the layout.
        """
        self.setMinimumWidth(400)
        # Create the big honkin' label and logo
        icon_pixmap = QPixmap(":/icon.png").scaledToWidth(64)
        icon_label = QLabel()
        icon_label.setPixmap(icon_pixmap)
        text_label = QLabel("Sidetone!")
        hb_label = QHBoxLayout()
        hb_label.addStretch(1)
        hb_label.addWidget(icon_label, 0)
        hb_label.addWidget(text_label, 0)
        hb_label.addStretch(1)

        # Create a list of QAudioInfo objects for inputs
        self.input_info_list = QAudioDeviceInfo.availableDevices(QAudio.AudioInput)
        if 0 == len(self.input_info_list):
            self.input_info_list = [QAudioDeviceInfo.defaultInputDevice()]
        # Create a combo box and populate it with names of inputs
        self.cb_inputs = QComboBox()
        self.cb_inputs.addItems([audio_info.deviceName() for audio_info in self.input_info_list])
        # Create a list of QAudioInfo objects for outputs
        self.otput_info_list = QAudioDeviceInfo.availableDevices(QAudio.AudioOutput)
        if 0 == len(self.otput_info_list):
            self.otput_info_list = [QAudioDeviceInfo.defaultOutputDevice()]
        self.status_bar.showMessage(
            "{} inputs {} otputs".format(len(self.input_info_list), len(self.otput_info_list)), 2000
        )
        # Create a combo box and populate it with names of outputs
        self.cb_otputs = QComboBox()
        self.cb_otputs.addItems([audio_info.deviceName() for audio_info in self.otput_info_list])
        # Lay those two out aligned to the outside
        hb_combos = QHBoxLayout()
        hb_combos.addWidget(self.cb_inputs, 1)
        hb_combos.addStretch(0)
        hb_combos.addWidget(self.cb_otputs, 1)
        # Create a volume slider from 0 to 100.
        self.volume = QSlider(Qt.Horizontal, self)
        self.volume.setMinimum(0)
        self.volume.setMaximum(100)
        self.volume.setTickInterval(10)
        self.volume.setTickPosition(QSlider.TicksBothSides)
        # Create a checkbox "Mute"
        self.mute = QCheckBox("Mute")
        # Put those together in a row squeezed in the center
        hb_volume = QHBoxLayout()
        hb_volume.addStretch(1)
        hb_volume.addWidget(self.volume, 1)
        hb_volume.addWidget(self.mute, 0)
        hb_volume.addStretch(1)
        # Stack all those up as this widget's layout
        vlayout = QVBoxLayout()
        vlayout.addLayout(hb_label)
        vlayout.addLayout(hb_combos)
        vlayout.addLayout(hb_volume)
        self.setLayout(vlayout)
Example #15
0
class TabSound(Tab):
    def __init__(self, obj):
        super().__init__(obj)
        self.mode = None
        self.colors = None
        self.count = 0
        # noinspection PyArgumentList
        self.inputdevices = QAudioDeviceInfo.availableDevices(
            QAudio.AudioInput)
        self.input = None
        if self.inputdevices:
            self.changeinput(0)
        self.stream = None
        self.timer = QTimer()
        # connections
        # noinspection PyUnresolvedReferences
        self.timer.timeout.connect(self.setcolorinterrupt)
        self.main.ui.plainTextEdit_bitdetector.textChanged.connect(
            self.checkinput)
        self.main.ui.comboBox_input.currentIndexChanged.connect(
            self.changeinput)
        self.main.ui.comboBox_effect_music.currentIndexChanged.connect(
            self.changetextedit)
        self.main.ui.pushButton_color_low.clicked.connect(self.colorselector)
        self.main.ui.pushButton_color_mid.clicked.connect(self.colorselector)
        self.main.ui.pushButton_color_high.clicked.connect(self.colorselector)
        self.main.ui.verticalSlider_lower_low.valueChanged.connect(
            self.changeslider)
        self.main.ui.verticalSlider_lower_mid.valueChanged.connect(
            self.changeslider)
        self.main.ui.verticalSlider_lower_high.valueChanged.connect(
            self.changeslider)
        self.main.ui.verticalSlider_higher_low.valueChanged.connect(
            self.changeslider)
        self.main.ui.verticalSlider_higher_mid.valueChanged.connect(
            self.changeslider)
        self.main.ui.verticalSlider_higher_high.valueChanged.connect(
            self.changeslider)
        self.main.ui.pushButton_sound_onoff.toggled.connect(
            self.soundbuttononoff)
        # update styles
        effects = ['Smooth', 'Change', 'Flash', 'Strob']
        self.main.ui.comboBox_effect_music.addItems(effects)
        inputs = [i.deviceName() for i in self.inputdevices]
        self.main.ui.comboBox_input.addItems(inputs)
        self.updatebuttons()

    def enabletab(self, flag):
        self.main.ui.comboBox_input.setEnabled(flag)
        self.main.ui.comboBox_effect_music.setEnabled(flag)
        self.main.ui.groupBox_freq.setEnabled(flag)
        self.main.ui.groupBox_bit_detect.setEnabled(flag)
        self.main.ui.pushButton_sound_onoff.setEnabled(flag)

    def updatebuttons(self):
        color = self.main.ui.pushButton_color_low.text()
        self.main.ui.pushButton_color_low.setStyleSheet(
            Color.plainbuttonstyle(color))
        color = self.main.ui.pushButton_color_mid.text()
        self.main.ui.pushButton_color_mid.setStyleSheet(
            Color.plainbuttonstyle(color))
        color = self.main.ui.pushButton_color_high.text()
        self.main.ui.pushButton_color_high.setStyleSheet(
            Color.plainbuttonstyle(color))

    def checkinput(self):
        text = self.main.ui.plainTextEdit_bitdetector.toPlainText()
        style = 'background-color: #ff0000' if not self.main.checktext(
            text) else ''
        self.main.ui.plainTextEdit_bitdetector.setStyleSheet(style)

    def changeinput(self, val):
        audio = QAudioFormat()
        audio.setSampleRate(44100)
        audio.setSampleType(QAudioFormat.UnSignedInt)
        audio.setSampleSize(8)
        audio.setCodec('audio/pcm')
        audio.setChannelCount(1)
        self.input = QAudioInput(self.inputdevices[val], audio)

    def changetextedit(self, val):
        self.main.ui.plainTextEdit_bitdetector.setEnabled(bool(val))

    def changeslider(self, val):  # 1 <= 2 <= 3 <= 4 <= 5 <= 6 (sliders)
        if self.main.sender() == self.main.ui.verticalSlider_lower_low:
            if val + 10 > self.main.ui.verticalSlider_higher_low.value():
                self.main.ui.verticalSlider_higher_low.setValue(val + 10)
        elif self.main.sender() == self.main.ui.verticalSlider_higher_low:
            if val > self.main.ui.verticalSlider_lower_mid.value():
                self.main.ui.verticalSlider_lower_mid.setValue(val)
            if val - 10 < self.main.ui.verticalSlider_lower_low.value():
                self.main.ui.verticalSlider_lower_low.setValue(val - 10)
        elif self.main.sender() == self.main.ui.verticalSlider_lower_mid:
            if val + 10 > self.main.ui.verticalSlider_higher_mid.value():
                self.main.ui.verticalSlider_higher_mid.setValue(val + 10)
            if val < self.main.ui.verticalSlider_higher_low.value():
                self.main.ui.verticalSlider_higher_low.setValue(val)
        elif self.main.sender() == self.main.ui.verticalSlider_higher_mid:
            if val > self.main.ui.verticalSlider_lower_high.value():
                self.main.ui.verticalSlider_lower_high.setValue(val)
            if val - 10 < self.main.ui.verticalSlider_lower_mid.value():
                self.main.ui.verticalSlider_lower_mid.setValue(val - 10)
        elif self.main.sender() == self.main.ui.verticalSlider_lower_high:
            if val + 10 > self.main.ui.verticalSlider_higher_high.value():
                self.main.ui.verticalSlider_higher_high.setValue(val + 10)
            if val < self.main.ui.verticalSlider_higher_mid.value():
                self.main.ui.verticalSlider_higher_mid.setValue(val)
        elif self.main.sender() == self.main.ui.verticalSlider_higher_high:
            if val - 10 < self.main.ui.verticalSlider_lower_high.value():
                self.main.ui.verticalSlider_lower_high.setValue(val - 10)

    def colorselector(self):
        # noinspection PyArgumentList
        dialog = QColorDialog().getColor()
        temp = '{:x}'.format(dialog.rgb())
        color = '#{}'.format(temp[2:])
        self.main.sender().setText(color)
        self.main.sender().setStyleSheet(Color.plainbuttonstyle(color))

    def soundbuttononoff(self, flag):
        self.main.settabsenable(not flag)
        if flag:
            self.mode = self.main.ui.comboBox_effect_music.currentText()
            text = self.main.ui.plainTextEdit_bitdetector.toPlainText()
            if self.main.checktext(text):
                self.colors = text.split()
                self.count = 0
                self.stream = self.input.start()
                timeout = 50 if self.mode == 'Smooth' else 200
                self.timer.start(timeout)
            else:
                self.main.ui.pushButton_sound_onoff.setChecked(False)
        else:
            self.input.stop()
            self.timer.stop()
            self.stream = None

    def setcolorinterrupt(self):
        val = self.stream.readAll().data()[-5000:]
        self.timer.stop()
        if val:
            from numpy import fft
            from numpy.ma import absolute
            val = [i - 128 for i in val]
            fur = absolute(fft.fft(val))
            freq = fft.fftfreq(len(val), d=1 / 44100)
            fur = fur[1:int(len(fur) / 2)]
            freq = freq[1:int(len(freq) / 2)]
            switch = {
                'Smooth': self.smooth,
                'Change': self.change,
                'Flash': self.flash,
                'Strob': self.strob
            }
            switch[self.mode](fur, freq)
        timeout = 50 if self.mode == 'Smooth' else 200
        self.timer.start(timeout)

    def smooth(self, val, freq):
        lowcolor = Color.hex2rgb(self.main.ui.pushButton_color_low.text())
        midcolor = Color.hex2rgb(self.main.ui.pushButton_color_mid.text())
        highcolor = Color.hex2rgb(self.main.ui.pushButton_color_high.text())
        lowlimits = [
            self.main.ui.verticalSlider_lower_low.value(),
            self.main.ui.verticalSlider_higher_low.value()
        ]
        midlimits = [
            self.main.ui.verticalSlider_lower_mid.value(),
            self.main.ui.verticalSlider_higher_mid.value()
        ]
        highlimits = [
            self.main.ui.verticalSlider_lower_high.value(),
            self.main.ui.verticalSlider_higher_high.value()
        ]
        lowval, midval, highval = [], [], []
        for i in range(len(freq)):
            if lowlimits[0] < freq[i] < lowlimits[1]:
                lowval.append(val[i])
        for i in range(len(freq)):
            if midlimits[0] < freq[i] < midlimits[1]:
                midval.append(val[i])
        for i in range(len(freq)):
            if highlimits[0] < freq[i] < highlimits[1]:
                highval.append(val[i])
        lowval = max(lowval) if lowval else 0
        midval = max(midval) if midval else 0
        highval = max(highval) if highval else 0
        mult = [
            self.main.ui.doubleSpinBox_mult_low.value(),
            self.main.ui.doubleSpinBox_mult_mid.value(),
            self.main.ui.doubleSpinBox_mult_high.value()
        ]
        noise = self.main.ui.horizontalSlider_noise.value()
        limiter = max(val) if max(val) > 4000 else 4000
        if limiter > noise:
            multval = [
                (lowval - noise) / (limiter - noise) if lowval > noise else 0,
                (midval - noise) / (limiter - noise) if midval > noise else 0,
                (highval - noise) / (limiter - noise) if highval > noise else 0
            ]
            r = (lowcolor[0] + midcolor[0] +
                 highcolor[0]) * mult[0] * multval[0]
            g = (lowcolor[1] + midcolor[1] +
                 highcolor[1]) * mult[1] * multval[1]
            b = (lowcolor[2] + midcolor[2] +
                 highcolor[2]) * mult[2] * multval[2]
            for i in range(6):
                self.main.setcolor(int(r), int(g), int(b), i)
        else:
            for i in range(6):
                self.main.setcolor(0, 0, 0, i)

    def change(self, val, freq):
        freqlow = self.main.ui.verticalSlider_lower_low.value()
        freqhigh = self.main.ui.verticalSlider_higher_low.value()
        limit = self.main.ui.horizontalSlider_noise.value()
        lvl = []
        for i in range(len(freq)):
            if freqlow < freq[i] < freqhigh:
                lvl.append(val[i])
        lvl = sum(lvl) / len(lvl)
        if lvl > limit:
            for i in range(6):
                self.main.setcolor(*Color.hex2rgb(self.colors[self.count]), i)
            self.count = self.count + 1 if self.count < len(
                self.colors) - 1 else 0

    def flash(self, val, freq):
        freqlow = self.main.ui.verticalSlider_lower_low.value()
        freqhigh = self.main.ui.verticalSlider_higher_low.value()
        limit = self.main.ui.horizontalSlider_noise.value()
        lvl = []
        for i in range(len(freq)):
            if freqlow < freq[i] < freqhigh:
                lvl.append(val[i])
        lvl = sum(lvl) / len(lvl)
        if lvl > limit:
            for i in range(6):
                self.main.setcolor(*Color.hex2rgb(self.colors[self.count]), i)
            for i in range(6):
                self.main.setcolor(0, 0, 0, i)
            self.count = self.count + 1 if self.count < len(
                self.colors) - 1 else 0

    def strob(self, val, freq):
        freqlow = self.main.ui.verticalSlider_lower_low.value()
        freqhigh = self.main.ui.verticalSlider_higher_low.value()
        limit = self.main.ui.horizontalSlider_noise.value()
        lvl = []
        for i in range(len(freq)):
            if freqlow < freq[i] < freqhigh:
                lvl.append(val[i])
        lvl = sum(lvl) / len(lvl)
        if lvl > limit:
            for _ in range(2):
                for i in range(6):
                    self.main.setcolor(*Color.hex2rgb(self.colors[self.count]),
                                       i)
                for __ in range(3):
                    for i in range(6):
                        self.main.setcolor(0, 0, 0, i)
            self.count = self.count + 1 if self.count < len(
                self.colors) - 1 else 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)
Example #17
0
class QtAudioInputRecorder(Recorder):
    def __init__(self, output_path: str, mw: aqt.AnkiQt,
                 parent: QWidget) -> None:
        super().__init__(output_path)

        self.mw = mw
        self._parent = parent

        from PyQt5.QtMultimedia import QAudioDeviceInfo, QAudioFormat, QAudioInput

        format = QAudioFormat()
        format.setChannelCount(1)
        format.setSampleRate(44100)
        format.setSampleSize(16)
        format.setCodec("audio/pcm")
        format.setByteOrder(QAudioFormat.LittleEndian)
        format.setSampleType(QAudioFormat.SignedInt)

        device = QAudioDeviceInfo.defaultInputDevice()
        if not device.isFormatSupported(format):
            format = device.nearestFormat(format)
            print("format changed")
            print("channels", format.channelCount())
            print("rate", format.sampleRate())
            print("size", format.sampleSize())
        self._format = format

        self._audio_input = QAudioInput(device, format, parent)

    def start(self, on_done: Callable[[], None]) -> None:
        self._iodevice = self._audio_input.start()
        self._buffer = b""
        self._iodevice.readyRead.connect(self._on_read_ready)  # type: ignore
        super().start(on_done)

    def _on_read_ready(self) -> None:
        self._buffer += cast(bytes, self._iodevice.readAll())

    def stop(self, on_done: Callable[[str], None]) -> None:
        def on_stop_timer() -> None:
            # read anything remaining in buffer & stop
            self._on_read_ready()
            self._audio_input.stop()

            if err := self._audio_input.error():
                showWarning(f"recording failed: {err}")
                return

            def write_file() -> None:
                # swallow the first 300ms to allow audio device to quiesce
                wait = int(44100 * self.STARTUP_DELAY)
                if len(self._buffer) <= wait:
                    return
                self._buffer = self._buffer[wait:]

                # write out the wave file
                wf = wave.open(self.output_path, "wb")
                wf.setnchannels(self._format.channelCount())
                wf.setsampwidth(self._format.sampleSize() // 8)
                wf.setframerate(self._format.sampleRate())
                wf.writeframes(self._buffer)
                wf.close()

            def and_then(fut: Future) -> None:
                fut.result()
                Recorder.stop(self, on_done)

            self.mw.taskman.run_in_background(write_file, and_then)

        # schedule the stop for half a second in the future,
        # to avoid truncating the end of the recording
        self._stop_timer = t = QTimer(self._parent)
        t.timeout.connect(on_stop_timer)  # type: ignore
        t.setSingleShot(True)
        t.start(500)
Example #18
0
class AudioAnalysis(QDialog):
    def __init__(self, mainwin, dir):
        super().__init__()
        self.main_Win = mainwin
        self.snd_record_ctr = 0 
        self.snd_play_ctr = 0
        self.snd_reset_ctr = 0
        self.is_snd_recording = None
        #
        self.audio = Audio(save_dir=dir)
        self.initAUD()
        self.initIF()
        self.initWaveList()

    def initIF(self):
        self.layout = QGridLayout(self)
        self.setLayout(self.layout)
        icon = QIcon()
        icon.addPixmap(QPixmap("./style/logo3.png"))
        self.setWindowIcon(icon)
        self.setWindowTitle("语音录制与分析")
        self.list_LW = QListWidget(self)
        self.list_LW.setMaximumWidth(160)
        class WaveSpectrum(QWidget):
            def __init__(self, parent=None, maindlg=None):
                super(WaveSpectrum, self).__init__(parent)
                self.main_Dlg = maindlg
                #self.pg_PL = pg.PlotWidget(enableMenu=False)
                self.audio = self.main_Dlg.audio
                self.layout = QGridLayout(self)
                self.setLayout(self.layout)
                self.pg_PL = pg.PlotWidget() #pg.plot(title="Three plot curves")
                self.pg_PL.hideButtons()
                self.layout.addWidget(self.pg_PL)               
                self.item = self.pg_PL.getPlotItem()
                self.item.hideButtons()
                self.item.setMouseEnabled(y=False)
                self.item.setYRange(0,20000)
                range = self.audio.rate/2
                self.item.setXRange(-range,range, padding=0)
                self.axis = self.item.getAxis("bottom")
                self.axis.setLabel("频率(赫兹)")
                
            def updatePlot(self):
               try:
                   data = np.fromstring(self.audio.block, 'int16')
                   #print(data)
                   T = 1.0/self.audio.rate
                   N = data.shape[0]
                   Fx = (1./N) * np.fft.fft(data) # 万一N==0
               except Exception as e:
                   print("??",e)
               else:
                   f = np.fft.fftfreq(N, T)
                   Fx = np.fft.fftshift(Fx)
                   f = np.fft.fftshift(f)
                   self.item.plot(x=f.tolist(), y=(np.absolute(Fx)).tolist(), clear=True)    
    
        self.wave_spectrum_PG = WaveSpectrum(maindlg=self)
        self.result_LB = QLabel(self)
        self.result_LB.setText("欢迎使用")
        self.running_SL = QSlider(Qt.Horizontal)
        self.running_SL.setMinimum(0)
        self.running_SL.setMaximum(100)
        self.running_SL.setStyleSheet("QSlider::handle:horizontal {background-color: #d91900;}")
        self.save_BT = QPushButton(self)
        self.save_BT.setText("保存与分析")
        self.save_BT.setMinimumSize(128,32)
        self.record_BT = QPushButton(self)
        self.record_BT.setText("开始录音")
        self.record_BT.setMinimumSize(144,32)
        self.play_BT = QPushButton(self)
        self.play_BT.setText("开始播放")
        self.play_BT.setMinimumSize(144,32)
        self.reset_BT = QPushButton(self)
        self.reset_BT.setText("停止")
        self.reset_BT.setMinimumSize(128,32)
               
        self.layout.addWidget(self.list_LW, 0,0,1,1)
        self.layout.addWidget(self.wave_spectrum_PG, 0,1, 1,3)
        self.layout.addWidget(self.result_LB, 1,0, 1,4)
        self.layout.addWidget(self.running_SL, 2,0, 1,4)
        self.layout.addWidget(self.save_BT, 3,0, 2,1)
        self.layout.addWidget(self.record_BT, 3,1, 2,1)
        self.layout.addWidget(self.play_BT, 3,2, 2,1)
        self.layout.addWidget(self.reset_BT, 3,3, 2,1)
        

        self.list_LW.itemClicked.connect(self.sel2Play)
        self.record_BT.clicked.connect(self.click2Record)
        self.running_SL.sliderReleased.connect(self.dragPosPlay) 
        # 注意这里得是用户主动的动作哟 另外如果需要点击位置定位的话还必须要重写mousePressEvent,这里就不弄了
        self.play_BT.clicked.connect(self.click2Play)
        self.reset_BT.clicked.connect(self.click2Reset)
        self.save_BT.clicked.connect(self.click2Save)
    
    def initWaveList(self):
        self.wave_dict = {"小黄":["catH1.wav",0],"小黄骚":["catH2.wav",0], "小黄又骚":["catH3.wav",0], "小黄又又骚":["catH4.wav",0]
                         ,"煤球":["catM1.wav",0],"煤球骚":["catM2.wav",0], "煤球又骚":["catM3.wav",0]
                         ,"老公":["laog.wav",0], "老婆":["laop.wav",0]}
        
        for k in self.wave_dict:
            item = QListWidgetItem()
            item.setText(k)
            item.setData(Qt.UserRole, self.wave_dict[k])
            self.list_LW.addItem(item)
            
    def initAUD(self):
        #
        info = QAudioDeviceInfo.defaultInputDevice()
        if (~info.isFormatSupported(self.audio.format)):
            # print("警告,设置的默认音频格式并不支持,将尝试采用最相近的支持格式")
            # 不知道这里面有什么神改动?
            self.audio.format  = info.nearestFormat(self.audio.format)
        #
        update_interval = 160
        self.audioRecorder = QAudioInput(self.audio.format)
        self.audioRecorder.setNotifyInterval(update_interval) #按毫秒ms 类似于QTimer的作用
        self.audioRecorder.notify.connect(self.processAudioData)
        self.audioRecorder_TD = QThread()
        self.audioRecorder.moveToThread(self.audioRecorder_TD)
        self.audioRecorder_TD.started.connect(self.startRecord)
        self.audioRecorder.stateChanged.connect(self.recordStopped)
        # 总结来说线程只是一个容器,里面执行的循环要是没法结束,强制退出也不好操作
        # 所以还是好好写好任务流然后发送信号比较合理
        self.audioPlayer = QAudioOutput(self.audio.format)
        self.audioPlayer.setNotifyInterval(update_interval)
        self.audioPlayer.notify.connect(self.processAudioData)
        self.audioPlayer_TD = QThread()
        self.audioPlayer.moveToThread(self.audioPlayer_TD)
        self.audioPlayer_TD.started.connect(self.startPlay)
        self.audioPlayer.stateChanged.connect(self.playStopped)
    
    #   
    def startRecord(self):
        self.audioRecorder.start(self.audio.record_buffer) # 独立出来主要就是为了传个参数进去
        
    def click2Record(self):
        if self.snd_play_ctr != 0:
            self.audioPlayer.suspend()
            self.audioPlayer.stop()
            self.audio.play_buffer.close()
            self.running_SL.setValue(0)
            self.audioPlayer_TD.quit()
            self.snd_play_ctr = 0
            self.play_BT.setText("开始播放")
        #
        self.is_snd_recording = True
        self.running_SL.setStyleSheet("QSlider::handle:horizontal {background-color: #d91900;}")
        self.running_SL.setValue(0)
        if self.snd_record_ctr == 0:
            self.audio.record_buffer.open(QIODevice.WriteOnly)
            self.audioRecorder_TD.start() #注意这里是分线程进行
            self.record_BT.setText("暂停录音")
            self.reset_BT.setText("停止录音")
        elif self.snd_record_ctr % 2 == 1:
            self.audioRecorder.suspend()
            self.result_LB.setText("录音暂停")
            self.record_BT.setText("继续录音")
        else: # self.snd_record_ctr % 2 == 0:
            self.audioRecorder.resume()
            self.record_BT.setText("暂停录音")
        self.snd_record_ctr += 1

    def recordStopped(self):
        if self.audioRecorder.state() == QAudio.StoppedState: #==2 #QAudio.IdleState: #==3;
            self.audioRecorder_TD.quit()

    def startPlay(self):
        self.audioPlayer.start(self.audio.play_buffer)

    def click2Play(self):
        if self.is_snd_recording == None:
            self.result_LB.setText("还没录音呢!!!")
        else:
            if self.snd_record_ctr % 2 == 1:
                self.audioRecorder.suspend()
                self.record_BT.setText("继续录音")
                self.snd_record_ctr += 1
            #
            self.is_snd_recording = False
            self.running_SL.setStyleSheet("QSlider::handle:horizontal {background-color: #007ad9;}")
            if self.snd_play_ctr == 0:
                data = self.audio.record_buffer.data()      
                self.audio.play_buffer.setData(data)
                self.audio.play_buffer.open(QIODevice.ReadOnly) # 要在关闭的情况下设置数据然后在以某种模式打开
                self.audioPlayer_TD.start()
                self.running_SL.setValue(0)
                self.start_time = 0
                # self.start_time = self.running_SL.value() / 100 * self.audio.duration
                # self.audioPlayer.setVolume(0.8)
                self.play_BT.setText("暂停播放")
                self.reset_BT.setText("停止播放")
            elif self.snd_play_ctr % 2 == 1:
                self.audioPlayer.suspend()
                self.result_LB.setText("播放暂停")
                self.play_BT.setText("继续播放")
            else:    
                self.audioPlayer.resume()
                self.play_BT.setText("暂停播放")
            self.snd_play_ctr += 1
    
    def playStopped(self):
        if self.audioPlayer.state() == QAudio.IdleState: #==3; #QAudio.StoppedState: #==2
            self.audioPlayer.stop()
            self.running_SL.setValue(0)
            self.audio.play_buffer.close()
            self.audioPlayer_TD.quit()
            self.snd_play_ctr = 0
            self.play_BT.setText("开始播放")
    
    def dragPosPlay(self):
        if self.is_snd_recording == None:
            self.running_SL.setValue(0)
        else:
            if self.is_snd_recording & (self.snd_record_ctr % 2 == 1):
                self.audioRecorder.suspend()
                self.record_BT.setText("继续录音")
                self.snd_record_ctr += 1
            if (not self.is_snd_recording) & (self.snd_play_ctr % 2 == 1):
                self.audioPlayer.suspend()
                self.play_BT.setText("继续播放")
                self.snd_play_ctr += 1
            self.is_snd_recording = False
            self.running_SL.setStyleSheet("QSlider::handle:horizontal {background-color: #007ad9;}")
            self.audioPlayer.stop()
            self.audio.play_buffer.close()
            self.audioPlayer_TD.quit()
            #
            data = self.audio.record_buffer.data()      
            self.audio.play_buffer.setData(data)
            self.audio.play_buffer.open(QIODevice.ReadOnly) # 要在关闭的情况下设置数据然后在以某种模式打开
            self.audioPlayer_TD.start()
            data_size = self.audio.record_buffer.data().size()
            sel_pcent = self.running_SL.value() / 100
            sel_size = int(sel_pcent * data_size)
            self.audio.pos = int(sel_pcent * (data_size / self.audio.chunksize)) # 重设第几个chunk开始播放
            self.start_time = int(sel_pcent * self.audio.duration) # 重设开始播放时间
            self.audio.play_buffer.seek(sel_size)
            self.snd_play_ctr = 1
            self.play_BT.setText("暂停播放")
    
    def sel2Play(self, item):
        c0 = (self.is_snd_recording == None)
        c1 = ((self.is_snd_recording == False) & (self.snd_play_ctr % 2 == 0))
        c2 = ((self.is_snd_recording == True) & (self.snd_record_ctr % 2 == 0))
        if (c0 | c1 | c2):
            self.cur_item = item
            sound_dir = "./sound/"
            #self.cur_wave = os.path.abspath(item.data(Qt.UserRole)[0])
            self.cur_wave = item.data(Qt.UserRole)[0]
            sound_path = os.path.join(sound_dir, self.cur_wave)
            with wave.open(sound_path, 'rb') as wf:
                data = wf.readframes(wf.getnframes())
                self.audio.play_buffer.setData(data)
                self.audio.play_buffer.open(QIODevice.ReadOnly)
                self.start_time = 0
                self.audio.duration = 10 # 随便给了个值,避免产生除0的问题其他没啥用
                self.audioPlayer_TD.start()           
    
    def click2Reset(self):
        if self.is_snd_recording == None:
            self.result_LB.setText("还没录音呢!!!")
        elif self.is_snd_recording:
            self.audioRecorder.stop()
            self.audio.record_buffer = QBuffer()
            self.snd_record_ctr = 0
            self.result_LB.setText("录音停止")
            self.record_BT.setText("开始录音")
        else: #not self.is_snd_recording:
            self.audioPlayer.stop()
            self.audio.pos = 0
            self.snd_play_ctr = 0
            self.result_LB.setText("播放停止")
            self.play_BT.setText("开始播放")
        self.running_SL.setValue(0)
        
    def click2Save(self):
        if self.is_snd_recording == None:
            self.result_LB.setText("还没录音呢!!!")
        elif self.is_snd_recording:
            self.audioRecorder.suspend()
        else:
            self.audioPlayer.suspend()
        #self.audio.save_path = QFileDialog().getSaveFileName(self.main_Dlg, "选个保存的地方吧", new_path)[0]
        # 注意末尾那个[0]别丢了,不然返回的是tuple类型
        self.audio.saveWave()
        self.snd_record_ctr = 0
        self.result_LB.setText("录音存于:{};刚刚应该是{}叫了:)".format(os.path.abspath(self.audio.save_path), self.getMinDist()))
        self.record_BT.setText("开始录音")
         
    def processAudioData(self):
        if self.is_snd_recording: #self.audioRecorder.state() == QAudio.ActiveState:
            self.audio.block = self.audio.record_buffer.data().right(self.audio.chunksize)
            self.audio.duration = self.audioRecorder.processedUSecs() # 注意这里是微秒!!!
            interval = 10
            self.running_SL.setValue((self.audio.duration / 1000000) % interval * (100 / interval))
            show_info = "已录制{:.1f}秒".format(self.audio.duration/1000000.0)
            self.result_LB.setText(show_info)
        else: # self.audioPlayer.state() == QAudio.ActiveState:
            # 试过chop 不过好像没有必要
            self.audio.block = self.audio.play_buffer.data().mid(self.audio.pos*self.audio.chunksize, self.audio.chunksize)
            self.audio.pos += 1
            self.running_SL.setValue((self.start_time + self.audioPlayer.processedUSecs())/self.audio.duration*100)
            show_info = "正在播放{:.1f}/{:.1f}秒".format((self.start_time + self.audioPlayer.processedUSecs())/1000000.0
                                                         ,self.audio.duration/1000000.0)
            self.result_LB.setText(show_info)
        self.wave_spectrum_PG.updatePlot()

    def getMFCC(self,path):
        (rate, sig) = scwav.read(path)
        mfcc_feature = mfcc(sig, rate)
        nmfcc = np.array(mfcc_feature)
        y, sr = librosa.load(path)
        return librosa.feature.mfcc(y, sr)
        
    def compareMFCC(self, demo_path):
        mfcc1 = self.getMFCC(self.audio.save_path)
        print(demo_path)
        mfcc2 = self.getMFCC(demo_path)
        norm = lambda x, y: nlnorm(x-y, ord=1)
        d, cost_matrix, acc_cost_matrix, path = dtw(mfcc1.T, mfcc2.T, dist=norm)
        return d
       
    def getMinDist(self):
        i = 1000000
        sound_dir = "./sound/"
        for k in self.wave_dict:
            self.wave_dict[k][1] = self.compareMFCC(os.path.join(sound_dir, self.wave_dict[k][0]))
            print("{}:{:.1f}".format(k, self.wave_dict[k][1]))
            i = min(i, self.wave_dict[k][1])
            if i == self.wave_dict[k][1]:
                min_k = k
        return min_k
Example #19
0
class SideToneWidget(QWidget):
    def __init__(self, parent, the_settings):
        super().__init__(parent)
        # Save link to main window
        self.main_window = parent
        # Save link to settings object
        self.settings = the_settings
        # Get the status bar
        self.status_bar = parent.statusBar()
        # just the time
        self.time = QTime()
        self.time.start()
        # Slot that will point to a QAudioInput some day
        self.input_device = None
        # Slot that will point to a QAudioOutput in time
        self.otput_device = None
        # set up layout, creating:
        #   self.input_info_list, list of QAudioInfo for inputs
        #   self.cb_inputs, combox of input names in same order
        #   self.otput_info_list, list of QAudioInfo for outputs
        #   self.cb_otputs, combox of output names in same order
        #   self.volume, volume slider
        #   self.mute, mute checkbox
        self._uic()
        # Connect up signals to slots. Up to this point, the changes that
        # _uic() made in e.g. the volume or mute, or the combobox selections,
        # raised signals that were not connected. Now connect the signals
        # so that user-changes go to our slots for handling.
        # Mute button goes to mute_change
        self.mute.stateChanged.connect(self.mute_change)
        # Change in volume goes to volume_change
        self.volume.valueChanged.connect(self.volume_change)
        # Changes in the combox selections go to in_device and ot_device
        self.cb_inputs.currentIndexChanged.connect(self.in_dev_change)
        self.cb_otputs.currentIndexChanged.connect(self.ot_dev_change)
        # Now pretend the user has made a selection of the in and out devices.
        # That should result in activating everythings.
        self.in_dev_change(self.cb_inputs.currentIndex())
        self.ot_dev_change(self.cb_otputs.currentIndex())

    # Method to disconnect the input and output devices, if they exist.
    # This is called prior to any change in device selection.
    # Note that the QWidget class has an existing method disconnect(),
    # and we do not want to override that, so that name is not used.

    def disconnect_devices(self):

        # If an output device exists, make it stop. That prevents it
        # trying to pull any data from the input device if any.
        if self.otput_device is not None:
            self.otput_device.stop()
        # If an input device exists, make it stop also. That means it
        # loses track of the output device it was formerly connected to.
        if self.input_device is not None:
            self.input_device.stop()

    # Method to connect the input and output devices, if both exist. This is
    # called after making any change in device selection.

    def reconnect_devices(self):

        if (self.input_device is not None) \
           and (self.otput_device is not None ) :

            # Connect the devices by asking the OUTput device for its
            # QIODevice, and passing that to the INput device's start()
            # method. This could equally well be done the other way,
            # by passing the input dev's IODevice to the output device.

            self.input_device.start(self.otput_device.start())
            #self.otput_device.start( self.input_device.start() )

            # In case the output device was just created, set its volume.
            self.set_volume()

    # Method to set the volume on the output device. (The input device volume
    # is always 1.0.) This is called on any change of the volume slider or
    # of the Mute button or of the output device choice.

    def set_volume(self):
        if self.mute.isChecked():
            # Mute is ON, set volume to 0 regardless of volume slider
            volume = 0.0
        else:
            # Mute is OFF, set volume to float version of volume slider
            volume = self.volume.value() / 100
        if self.otput_device:
            # an output device exists (almost always true), set it
            self.otput_device.setVolume(volume)

    # Slot entered upon any change in the volume slider widget.
    def volume_change(self, new_level):
        if self.mute.isChecked():
            # The Mute button is ON; assume the user wants it OFF, else why
            # move the slider? Note this causes a call to set_volume().
            self.mute.setChecked(False)
        else:
            # The Mute button is OFF, just change the volume.
            self.set_volume()

    # Slot entered upon toggling of the mute switch, by the user or by the
    # code calling mute.setChecked(). Make sure the volume is set appropriately.
    def mute_change(self, onoff):
        self.set_volume()

    # Slots for selection of the input and output devices. On startup we have
    # neither an input nor an output device. We do not know which combox the
    # user will fiddle with first.

    # Slot entered upon any change in the selection of the input device
    # combo box. The argument is the new index of the list of values.

    def in_dev_change(self, new_index):

        # Disconnect and stop the devices if they are connected.
        self.disconnect_devices()

        self.input_device = None  # device object goes out of scope

        # Get the QAudioDeviceInfo corresponding to this index of the combox.
        audio_info = self.input_info_list[new_index]

        # Create a new QAudioInput based on that.
        preferred_format = audio_info.preferredFormat()
        self.input_device = QAudioInput(audio_info, preferred_format)

        # the input device volume is always 1.0, wide open.
        self.input_device.setVolume(1.0)

        # The choice of buffer size has a major impact on the lag. It needs
        # to be small or there is severe echo; but if it is too small, there
        # is a sputtering or "motor-boating" effect.
        self.input_device.setBufferSize(384)

        # hook up possible debug status display
        self.input_device.stateChanged.connect(self.in_dev_state_change)

        # reconnect the devices if possible.

        self.reconnect_devices()

    # Slot entered upon any change in the selection of output. The argument
    # is the index to the list of output devices in the combobox.

    def ot_dev_change(self, new_index):
        print('index', new_index)
        # Disconnect and stop the devices if they are connected.
        self.disconnect_devices()

        self.otput_device = None  # device object goes out of scope

        # Get the QAudioDeviceInfo corresponding to this index of the combox.
        audio_info = self.otput_info_list[new_index]

        # Create a new QAudioOutput based on that.
        preferred_format = audio_info.preferredFormat()
        self.otput_device = QAudioOutput(audio_info, preferred_format)
        self.otput_device.setVolume(0)  # reconnect will set correct volume

        # hook up possible debug status display
        self.otput_device.stateChanged.connect(self.ot_dev_state_change)

        # reconnect the devices if possible. Which also sets the volume.

        self.reconnect_devices()

    # Show some text in the main-window status bar for 1 second, more or less.
    def show_status(self, text, duration=1000):
        self.status_bar.showMessage(text, duration)

    # Slots called on any "state" change of an audio device. Optionally
    # show the state in the main window status bar.
    def in_dev_state_change(self, new_state):
        #self.show_status(
        #'{} in dev state {}'.format(self.time.elapsed(),int(new_state))
        #)
        pass

    def ot_dev_state_change(self, new_state):
        #self.show_status(
        #'{} ot dev state {}'.format(self.time.elapsed(),int(new_state))
        #)
        pass

    # Close events are only received by a top-level widget. When our top-level
    # widget gets one, indicating the app is done, it calls this method.

    def closeEvent(self, event):
        # if we have devices, make them stop.
        self.disconnect_devices()

        # if the devices exist, reset them and then trash them.
        if self.otput_device is not None:
            self.otput_device.reset()
            self.otput_device = None
        if self.input_device is not None:
            self.input_device.reset()
            self.input_device = None

        # Save the current selection of the input and output combo boxes,
        # in the settings file.
        in_dev_name = self.cb_inputs.currentText()
        self.settings.setValue('in_dev_name', in_dev_name)
        ot_dev_name = self.cb_otputs.currentText()
        self.settings.setValue('ot_dev_name', ot_dev_name)

        # Save the volume setting and mute status in the settings.
        self.settings.setValue('volume', self.volume.value())
        self.settings.setValue('mute_status', int(self.mute.isChecked()))

    def _uic(self):
        '''
    set up our layout which consists of:

                 Big Honkin' Label
        [input combobox]    [output combobox]
               [volume slider]  [x] Mute

    Hooking the signals to useful slots is the job
    of __init__. Here just make the layout.
        '''
        self.setMinimumWidth(400)
        # Create the big honkin' label and logo
        icon_pixmap = QPixmap(':/icon.png').scaledToWidth(64)
        icon_label = QLabel()
        icon_label.setPixmap(icon_pixmap)
        text_label = QLabel("Sidetone!")
        hb_label = QHBoxLayout()
        hb_label.addStretch(1)
        hb_label.addWidget(icon_label, 0)
        hb_label.addWidget(text_label, 0)
        hb_label.addStretch(1)

        # Create a list of QAudioInfo objects for inputs
        self.input_info_list = QAudioDeviceInfo.availableDevices(
            QAudio.AudioInput)
        if 0 == len(self.input_info_list):
            self.input_info_list = [QAudioDeviceInfo.defaultInputDevice()]
        # Make a list of the name-strings for those items.
        in_dev_names = [
            audio_info.deviceName() for audio_info in self.input_info_list
        ]
        # Create a combo box and populate it with those names
        self.cb_inputs = QComboBox()
        self.cb_inputs.addItems(in_dev_names)
        # If the in_dev_name from the previous run is in the current list,
        # make it current, otherwise pick the first item.
        in_dev_name = self.settings.value('in_dev_name', 'unknown')
        if in_dev_name in in_dev_names:
            self.cb_inputs.setCurrentIndex(in_dev_names.index(in_dev_name))
        else:
            self.cb_inputs.setCurrentIndex(0)

        # Create a list of QAudioInfo objects for outputs
        self.otput_info_list = QAudioDeviceInfo.availableDevices(
            QAudio.AudioOutput)
        if 0 == len(self.otput_info_list):
            self.otput_info_list = [QAudioDeviceInfo.defaultOutputDevice()]
        # Make a list of the name-strings of those things
        ot_dev_names = [
            audio_info.deviceName() for audio_info in self.otput_info_list
        ]
        # Create a combo box and populate it with those names
        self.cb_otputs = QComboBox()
        self.cb_otputs.addItems(ot_dev_names)
        # If the ot_dev_name from the previous run is in the current list,
        # make it the current choice in the box.
        ot_dev_name = self.settings.value('ot_dev_name', 'unknown')
        if ot_dev_name in ot_dev_names:
            self.cb_otputs.setCurrentIndex(ot_dev_names.index(ot_dev_name))
        else:
            self.cb_otputs.setCurrentIndex(0)

        #self.show_status(
        #'{} inputs {} otputs'.format(len(self.input_info_list),len(self.otput_info_list))
        #)
        # Create a combo box and populate it with names of outputs

        # Lay those two out aligned to the outside
        hb_combos = QHBoxLayout()
        hb_combos.addWidget(self.cb_inputs, 1)
        hb_combos.addStretch(0)
        hb_combos.addWidget(self.cb_otputs, 1)

        # Create a volume slider from 0 to 100.
        self.volume = QSlider(Qt.Horizontal, self)
        self.volume.setMinimum(0)
        self.volume.setMaximum(100)
        self.volume.setTickInterval(10)
        self.volume.setTickPosition(QSlider.TicksBothSides)
        # set the volume slider to the value from the previous run, or zero.
        self.volume.setValue(self.settings.value('volume', 0))

        # Create a checkbox "Mute"
        self.mute = QCheckBox('Mute')
        # Set it to the value at the end of the last run, or to True
        self.mute.setChecked(bool(self.settings.value('mute_status', 1)))

        # Put those together in a row squeezed in the center
        hb_volume = QHBoxLayout()
        hb_volume.addStretch(1)
        hb_volume.addWidget(self.volume, 1)
        hb_volume.addWidget(self.mute, 0)
        hb_volume.addStretch(1)

        # Stack all those up as this widget's layout
        vlayout = QVBoxLayout()
        vlayout.addLayout(hb_label)
        vlayout.addLayout(hb_combos)
        vlayout.addLayout(hb_volume)
        self.setLayout(vlayout)
Example #20
0
class Recorder(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Recorder, self).__init__()
        self.setupUi(self)
        self.output = QFile()
        self.audio = QAudioInput()
        self.NEED_ASR = False
        self.Open = True

        self.th1 = threading.Thread(target=self.ASR)
        self.th1.start()

        self.Pause_Button.clicked.connect(self.toggle_pause)
        self.Record_Button.clicked.connect(self.toggle_record)

    def closeEvent(self, event):
        self.Open = False

    def toggle_record(self):
        if self.Record_Button.text() == "开始录音":
            self.statusbar.showMessage("开始录音")
            self.setup()
            self.audio.start(self.output)
            self.Record_Button.setText("停止")
            self.Pause_Button.setText("暂停")
            self.Pause_Button.setEnabled(True)
        else:
            self.audio.stop()
            self.output.close()
            self.Pause_Button.setText("暂停")
            self.Record_Button.setText("开始录音")
            self.statusbar.showMessage("正在使用百度智能云识别,请稍等")
            self.NEED_ASR = True

    def toggle_pause(self):
        if self.Pause_Button.text() == "暂停":
            self.Pause_Button.setText("继续")
            self.audio.suspend()

        else:
            self.Pause_Button.setText("暂停")
            self.audio.resume()

    def ASR(self):
        while self.Open:
            print(1)
            if self.NEED_ASR:
                try:
                    text = ASR().Baidu_ASR("record.pcm")
                    print(text)
                    if text['err_msg'] == 'success.':
                        self.Text_plainTextEdit.setPlainText(text['result'][0])
                        self.statusbar.showMessage("识别成功")

                    else:
                        self.statusbar.showMessage("识别失败,请再说一遍")
                except:
                    self.statusbar.showMessage("网络故障,请检查网络设置以及百度智能云账号")

                self.NEED_ASR = False
            else:
                pass

    def setup(self):
        self.output.setFileName("record.pcm")
        self.output.open(QIODevice.WriteOnly | QIODevice.Truncate)
        settings = QAudioFormat()
        settings.setCodec("audio/pcm")
        settings.setSampleRate(16000)
        settings.setSampleSize(16)
        settings.setChannelCount(1)
        settings.setByteOrder(QAudioFormat.LittleEndian)
        settings.setSampleType(QAudioFormat.SignedInt)
        self.audio = QAudioInput(settings)
Example #21
0
class SideToneWidget(QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        # Save link to main window
        self.main_window = parent
        # Get the status bar
        self.status_bar = parent.statusBar()
        # Slot that will point to a QAudioInput some day
        self.input_device = None
        # Slot that will point to a QAudioOutput in time
        self.otput_device = None
        # set up layout, creating:
        # self.input_info_list, list of QAudioInfo for inputs
        # self.cb_inputs, combox of input names in same order
        # self.otput_info_list, list of QAudioInfo for outputs
        # self.cb_otputs, combox of output names in same order
        # self.volume, volume slider
        # self.mute, mute checkbox
        self._uic()
        # Connect up signals to slots.
        # Changes in the comboxes go to in_device and ot_device
        self.cb_inputs.currentIndexChanged.connect(self.in_dev_change)
        self.cb_otputs.currentIndexChanged.connect(self.ot_dev_change)
        # Mute button goes to mute_change
        self.mute.stateChanged.connect(self.mute_change)
        # Change in volume goes to volume_change
        self.volume.valueChanged.connect(self.volume_change)
        # Start with the mute switch on. This triggers the above two signals.
        self.mute.setChecked(True)

    # Slot for any change in volume (or mute). If we have an output device
    # then convert level to a real and pass to the output device. If the new
    # level is 0, tell the device to stop; if nonzero, tell it to start.
    # Note we don't do anything about the input device level, it is always 1.0
    def volume_change(self, new_level):
        if self.otput_device:  # we have an output device
            self.otput_device.setVolume(self.volume.value() / 100)
            if new_level == 0:  # looks like a mute
                # tell the output device to stop just in case it
                # doesn't know about volume control.
                self.otput_device.stop()
            else:  # non-zero level, if the output is stopped, start it
                if self.otput_device.state() == QAudio.StoppedState:
                    self.otput_device.start()

    # Slot for mute switch. Note that any change to the volume slider
    # generates a signal to the volume_change slot.
    def mute_change(self, onoff):
        if onoff:
            # Mute has been clicked ON. Remember the current volume.
            # Turn the volume to zero.
            self.volume_level = self.volume.value()
            self.volume.setValue(0)
        else:
            # Mute has been clicked OFF. If we do not yet have input and
            # output devices, get them. Then reset the old volume level.
            if self.otput_device is None:
                # We are starting up and have no devices. Fake a call to
                # the checkbox-change entries thus creating devices.
                self.in_dev_change(self.cb_inputs.currentIndex())
                self.ot_dev_change(self.cb_inputs.currentIndex())
            self.volume.setValue(self.volume_level)

    # Slots for changes in the selection of the input- and output-device
    # combo boxes. On startup we have neither an input nor an output device.
    # We do not know which combox the user will fiddle with first. So either
    # has to assume that the other device may not yet exist.
    #
    # On a change of input choice: if we have an input device, get rid of it.
    # Create a new input device. Set its level to 1.0. If we
    # have an output, connect the two.

    def in_dev_change(self, new_index):
        if self.input_device:
            if self.otput_device:
                self.otput_device.stop()
            self.input_device.stop()
            self.input_device = None  # goodby object
        # Get the QAudioDeviceInfo corresponding to this index of the combox.
        audio_info = self.input_info_list[new_index]
        # Create a new QAudioInput based on that.
        preferred_format = audio_info.preferredFormat()
        self.input_device = QAudioInput(audio_info, preferred_format)
        self.input_device.setVolume(1.0)
        self.input_device.setBufferSize(384)
        # If we have an output device, redirect it to this input. This is
        # done by asking the input device for its QIODevice, and passing that
        # to the output device's start() method.
        if self.otput_device:
            self.input_device.start(self.otput_device.start())
            #self.otput_device.start( self.input_device.start() )

    # On a change in the selection of output choice: If we have an output
    # device, get rid of it. Create a new output device. If we have an input
    # device, connect the two. Set the output level from the volume slider.

    def ot_dev_change(self, new_index):
        if self.otput_device:
            if self.input_device:
                self.input_device.stop()
            self.otput_device.stop()
            self.otput_device = None
        audio_info = self.otput_info_list[new_index]
        preferred_format = audio_info.preferredFormat()
        self.otput_device = QAudioOutput(audio_info, preferred_format)
        self.otput_device.setVolume(self.volume.value() / 100)
        #self.otput_device.setBufferSize( 384 )
        if self.input_device:
            self.input_device.start(self.otput_device.start())
            #self.otput_device.start( self.input_device.start() )

    def _uic(self):
        '''
    set up our layout which consists of:

                 Big Honkin' Label
        [input combobox]    [output combobox]
               [volume slider]  [x] Mute

    hooking put the signals to useful slots is the job
    of __init__. Here just make the layout.
        '''
        self.setMinimumWidth(400)
        # Create the big honkin' label and logo
        icon_pixmap = QPixmap(':/icon.png').scaledToWidth(64)
        icon_label = QLabel()
        icon_label.setPixmap(icon_pixmap)
        text_label = QLabel("Sidetone!")
        hb_label = QHBoxLayout()
        hb_label.addStretch(1)
        hb_label.addWidget(icon_label, 0)
        hb_label.addWidget(text_label, 0)
        hb_label.addStretch(1)

        # Create a list of QAudioInfo objects for inputs
        self.input_info_list = QAudioDeviceInfo.availableDevices(
            QAudio.AudioInput)
        if 0 == len(self.input_info_list):
            self.input_info_list = [QAudioDeviceInfo.defaultInputDevice()]
        # Create a combo box and populate it with names of inputs
        self.cb_inputs = QComboBox()
        self.cb_inputs.addItems(
            [audio_info.deviceName() for audio_info in self.input_info_list])
        # Create a list of QAudioInfo objects for outputs
        self.otput_info_list = QAudioDeviceInfo.availableDevices(
            QAudio.AudioOutput)
        if 0 == len(self.otput_info_list):
            self.otput_info_list = [QAudioDeviceInfo.defaultOutputDevice()]
        self.status_bar.showMessage(
            '{} inputs {} otputs'.format(len(self.input_info_list),
                                         len(self.otput_info_list)), 2000)
        # Create a combo box and populate it with names of outputs
        self.cb_otputs = QComboBox()
        self.cb_otputs.addItems(
            [audio_info.deviceName() for audio_info in self.otput_info_list])
        # Lay those two out aligned to the outside
        hb_combos = QHBoxLayout()
        hb_combos.addWidget(self.cb_inputs, 1)
        hb_combos.addStretch(0)
        hb_combos.addWidget(self.cb_otputs, 1)
        # Create a volume slider from 0 to 100.
        self.volume = QSlider(Qt.Horizontal, self)
        self.volume.setMinimum(0)
        self.volume.setMaximum(100)
        self.volume.setTickInterval(10)
        self.volume.setTickPosition(QSlider.TicksBothSides)
        # Create a checkbox "Mute"
        self.mute = QCheckBox('Mute')
        # Put those together in a row squeezed in the center
        hb_volume = QHBoxLayout()
        hb_volume.addStretch(1)
        hb_volume.addWidget(self.volume, 1)
        hb_volume.addWidget(self.mute, 0)
        hb_volume.addStretch(1)
        # Stack all those up as this widget's layout
        vlayout = QVBoxLayout()
        vlayout.addLayout(hb_label)
        vlayout.addLayout(hb_combos)
        vlayout.addLayout(hb_volume)
        self.setLayout(vlayout)
Example #22
0
class QmyMainWindow(QMainWindow): 

   def __init__(self, parent=None):
      super().__init__(parent)    #调用父类构造函数,创建窗体
      self.ui=Ui_MainWindow()     #创建UI对象
      self.ui.setupUi(self)       #构造UI界面

      self.ui.progBar_Max.setMaximum(256)
      self.ui.progBar_Min.setMaximum(256)
      self.ui.progBar_Diff.setMaximum(256)

      self.ui.sliderVolumn.setMaximum(100)
      self.ui.sliderVolumn.setValue(100)

      self.ui.comboDevices.clear()
      self.__deviceList=QAudioDeviceInfo.availableDevices(QAudio.AudioInput) #音频输入设备列表
      for i in range(len(self.__deviceList)):
         device=self.__deviceList[i]    #QAudioDeviceInfo类
         self.ui.comboDevices.addItem(device.deviceName())

##      self.__deviceInfo =None   #当前设备信息,QAudioDeviceInfo
      self.audioDevice=None       #音频输入设备,QAudioInput
      self.BUFFER_SIZE=4000

      self.ioDevice=None      #第1种读取方法,内建的IODevice

##      self.externalReader=None        #第2种读取方法,外建的IODevice

      self.recordFile=QFile()      #第3种读取方法,使用QFile直接写入文件

      if len(self.__deviceList)>0:
         self.ui.comboDevices.setCurrentIndex(0) #触发comboDevices的信号currentIndexChanged()
##         self.__deviceInfo =deviceList[0]
      else:
         self.ui.actStart.setEnabled(False)
         self.ui.actDeviceTest.setEnabled(False)
         self.ui.groupBoxDevice.setTitle("支持的音频输入设置(无设备)")
      

##  ==============自定义功能函数========================
   def __getSampleTypeStr(self,sampleType):
      result="Unknown"
      if sampleType==QAudioFormat.SignedInt:
         result = "SignedInt"
      elif sampleType==QAudioFormat.UnSignedInt:
         result = "UnSignedInt"
      elif sampleType==QAudioFormat.Float:
         result = "Float"
      elif sampleType==QAudioFormat.Unknown:
         result = "Unknown"
         
      return result

   def __getByteOrderStr(self,endian):
      if (endian==QAudioFormat.LittleEndian):
         return "LittleEndian"
      else:
         return "BigEndian"
      

##  ==============event处理函数==========================
        
        
##  ==========由connectSlotsByName()自动连接的槽函数============
      
   @pyqtSlot(int)   ##选择音频输入设备
   def on_comboDevices_currentIndexChanged(self,index):        
      deviceInfo =self.__deviceList[index]   #当前音频设备,QAudioDeviceInfo类型
      self.ui.comboCodec.clear()             
      codecs = deviceInfo.supportedCodecs()  #支持的音频编码,字符串列表
      for strLine in codecs:
         self.ui.comboCodec.addItem(strLine)

      self.ui.comboSampleRate.clear()  #支持的采样率
      sampleRates = deviceInfo.supportedSampleRates()  #QList<int>
      for i in  sampleRates:
         self.ui.comboSampleRate.addItem("%d"% i)

      self.ui.comboChannels.clear()    #支持的通道数
      Channels = deviceInfo.supportedChannelCounts() #QList<int> 
      for i in Channels:
         self.ui.comboChannels.addItem("%d"%i )

      self.ui.comboSampleTypes.clear() #支持的采样点类型
      sampleTypes = deviceInfo.supportedSampleTypes() #QList<QAudioFormat::SampleType>
      for i in  sampleTypes:
         sampTypeStr=self.__getSampleTypeStr(i)
         self.ui.comboSampleTypes.addItem(sampTypeStr,i)
         
      self.ui.comboSampleSizes.clear() #采样点大小
      sampleSizes = deviceInfo.supportedSampleSizes() #QList<int>
      for i in  sampleSizes:
         self.ui.comboSampleSizes.addItem("%d"%i)

      self.ui.comboByteOrder.clear() #字节序
      endians = deviceInfo.supportedByteOrders()  #QList<QAudioFormat::Endian> 
      for i in endians:
         self.ui.comboByteOrder.addItem(self.__getByteOrderStr(i))

   @pyqtSlot()   ##使用内建IODevice
   def on_radioSaveMode_Inner_clicked(self):
      self.ui.groupBox_disp.setVisible(True)
      
   @pyqtSlot()   ##使用QFile对象(test.raw)
   def on_radioSaveMode_QFile_clicked(self):
      self.ui.groupBox_disp.setVisible(False)

   @pyqtSlot(int)   ##调节录音音量
   def on_sliderVolumn_valueChanged(self,value):
      self.ui.LabVol.setText("录音音量(%d%%)"%value)


   @pyqtSlot()   ##测试音频输入设备是否支持选择的设置
   def on_actDeviceTest_triggered(self):
      settings=QAudioFormat()
      settings.setCodec(self.ui.comboCodec.currentText())
      settings.setSampleRate(int(self.ui.comboSampleRate.currentText()))
      settings.setChannelCount(int(self.ui.comboChannels.currentText()))

      k=self.ui.comboSampleTypes.currentData()
      settings.setSampleType(k)  #QAudioFormat.SampleType

      settings.setSampleSize(int(self.ui.comboSampleSizes.currentText()))

      if (self.ui.comboByteOrder.currentText()=="LittleEndian"):
         settings.setByteOrder(QAudioFormat.LittleEndian)
      else:
         settings.setByteOrder(QAudioFormat.BigEndian)

      index=self.ui.comboDevices.currentIndex()
      deviceInfo =self.__deviceList[index]  #当前音频设备

      if deviceInfo.isFormatSupported(settings):
         QMessageBox.information(self,"消息","测试成功,设备支持此设置")
      else:
         QMessageBox.critical(self,"错误","测试失败,设备不支持此设置")

   @pyqtSlot()   ##开始音频输入
   def on_actStart_triggered(self):
      audioFormat=QAudioFormat() #使用固定格式
      audioFormat.setSampleRate(8000)
      audioFormat.setChannelCount(1)
      audioFormat.setSampleSize(8)
      audioFormat.setCodec("audio/pcm")
      audioFormat.setByteOrder(QAudioFormat.LittleEndian)
      audioFormat.setSampleType(QAudioFormat.UnSignedInt)

      index=self.ui.comboDevices.currentIndex()
      deviceInfo =self.__deviceList[index]  #当前音频设备

      if (False== deviceInfo.isFormatSupported(audioFormat)):
         QMessageBox.critical(self,"错误","测试失败,输入设备不支持此设置")
         return

      self.audioDevice = QAudioInput(deviceInfo,audioFormat) #音频输入设备
      self.audioDevice.setBufferSize(self.BUFFER_SIZE)   #设置的缓冲区大小,字节数,并不一定等于实际数据块大小
      self.audioDevice.stateChanged.connect(self.do_stateChanged)  #状态变化


   ##1. 使用 start()->QIODevice 启动,返回的内置的IODevice, pull mode,利用readyRead()信号读出数据
      if self.ui.radioSaveMode_Inner.isChecked():
         self.ioDevice=self.audioDevice.start()  #返回内建的IODevice
         self.ioDevice.readyRead.connect(self.do_IO_readyRead)

   ## 2. 自定义流设备QWAudioBlockReader,push mode, start(QIODevice),不行
   ##      if self.ui.radioSaveMode_External.isChecked():
   ##         self.externalReader = QmyAudioReader()
   ##         self.externalReader.open(QIODevice.WriteOnly)
   ##         self.externalReader.updateBlockInfo.connect(self.do_updateBlockInfo)
   ##         self.audioDevice.start(self.externalReader)  #使用外建的IODevice
         
      
   ##3. 写入文件,用 start(QIODevice)启动
      if self.ui.radioSaveMode_QFile.isChecked():
         self.recordFile.setFileName("test.raw") 
         self.recordFile.open(QIODevice.WriteOnly)
         self.audioDevice.start(self.recordFile)  


   @pyqtSlot()   ##停止音频输入
   def on_actStop_triggered(self):
      self.audioDevice.stop()
      self.audioDevice.deleteLater()
      
   ##1. 使用 QIODevice  =start()返回的内置的IODevice, pull mode,利用readyRead()信号读出数据
      #无需处理,停止后self.ioDevice自动变为无效

   ##2. 外部IODevice接收音频输入数据的流设备
   ##      if self.ui.radioSaveMode_External.isChecked():
   ##         self.externalReader.close()
   ##         self.externalReader.updateBlockSize.disconnect(self.do_updateBlockInfo)
   ##         del self.externalReader  #删除外建设备
      
   ##3. 写入文件,start(QIODevice) 启动
      if self.ui.radioSaveMode_QFile.isChecked():
         self.recordFile.close() #关闭文件
      

        
##  =============自定义槽函数===============================        
##1. 使用QIODevice* start()返回的内置的IODevice, pull mode,利用readyRead()信号读出数据
   def do_IO_readyRead(self):    ##内建IODevice,读取缓冲区数据
      self.ui.LabBufferSize.setText("bufferSize()=%d"
                                    %self.audioDevice.bufferSize())

      byteCount = self.audioDevice.bytesReady() #可以读取的字节数
      self.ui.LabBytesReady.setText("bytesReady()=%d"%byteCount)

      if byteCount>self.BUFFER_SIZE:
         byteCount=self.BUFFER_SIZE
      
      buffer=self.ioDevice.read(byteCount)  #返回的是bytes类型,便于处理
   ##      buffer=self.ioDevice.readAll()  #不能用readAll()读取,返回的是QByteArray,需要再转换为bytes
      
   ##      print(type(buffer))
   ##      print(buffer)
      
      maxSize=len(buffer)
   ##      print(maxSize)

      self.ui.LabBlockSize.setText("IODevice数据字节数=%d"%maxSize)

      maxV=0
      minV=255
      for k in range(maxSize):
         V=buffer[k]  #取一个字节,整数
         if V>maxV:
            maxV=V   #求最大值
         if V<minV:
            minV=V   #求最小值

      self.ui.progBar_Max.setValue(maxV)
      self.ui.progBar_Min.setValue(minV)
      self.ui.progBar_Diff.setValue(maxV-minV)


   def do_stateChanged(self,state):    ##设备状态变化
      isStoped=(state== QAudio.StoppedState) #停止状态
      self.ui.groupBox_saveMode.setEnabled(isStoped)
      self.ui.sliderVolumn.setEnabled(isStoped)
      self.ui.actStart.setEnabled(isStoped)
      self.ui.actStop.setEnabled(not isStoped)
      self.ui.actDeviceTest.setEnabled(isStoped)
      self.ui.sliderVolumn.setEnabled(isStoped)

      if  state== QAudio.ActiveState:
         self.ui.statusBar.showMessage("state: ActiveState")
      elif state== QAudio.SuspendedState:
         self.ui.statusBar.showMessage("state: SuspendedState")
      elif state== QAudio.StoppedState:
         self.ui.statusBar.showMessage("state: StoppedState")
      elif state== QAudio.IdleState:
         self.ui.statusBar.showMessage("state: IdleState")
      elif state== QAudio.InterruptedState:
         self.ui.statusBar.showMessage("state: InterruptedState")