Exemple #1
0
class QVoiceRecorder(object):
    def __init__(self):
        pass

    def initAudioInput(self, filepath):

        self.recorder = QAudioRecorder()

        self.settings = QAudioEncoderSettings()
        self.settings.setCodec("audio/vorbis")
        self.recorder.setContainerFormat("ogg")
        #self.settings.setQuality(QtMultimedia.HighQuality)

        self.recorder.setEncodingSettings(self.settings)

        url = QtCore.QUrl.fromLocalFile(
            QtCore.QFileInfo(filepath).absoluteFilePath())
        self.recorder.setOutputLocation(url)

    def start(self):
        self.recorder.record()

    def stop(self):
        self.recorder.pause()
        self.recorder.stop()
        self.recorder.stop()
Exemple #2
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # Controles principales para organizar la ventana.

        self.setupConstants()

        self.widget = QWidget(self)

        # tha main layout
        self.layout = QVBoxLayout()

        # the top box with file selections
        self.input_layout = QHBoxLayout()
        self.output_layout = QHBoxLayout()
        self.bottom_layout = QHBoxLayout()
        self.volume_box = QHBoxLayout()

        # video playback section
        self.video_widget = QVideoWidget(self)
        self.media_player = QMediaPlayer()
        self.media_player.setVideoOutput(self.video_widget)

        # initialize audio recording section
        self.recorder = QAudioRecorder()

        # labels
        self.volume_label = QLabel()
        self.volume_label.setText("Volume")

        # Buttons for the I/O files selection
        self.input_file_button = QPushButton("Video Input", self)
        self.output_file_button = QPushButton("Audio output", self)

        # path/file line edits
        self.input_file_edit = QLineEdit()
        self.output_file_edit = QLineEdit()
        self.play_button = QPushButton("", self)
        self.play_button.setIcon(self.play_normal_icon)
        self.play_button.resize(150, 150)
        self.stop_button = QPushButton("", self)
        self.stop_button.setIcon(self.stop_normal_icon)
        self.record_button = QPushButton("", self)
        self.record_button.setCheckable(True)
        self.record_button.setIcon(self.rec_icon)

        self.seek_slider = QSlider(Qt.Horizontal)

        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(self.media_player.volume())

        self.input_layout.addWidget(self.input_file_button)
        self.input_layout.addWidget(self.input_file_edit)

        self.output_layout.addWidget(self.output_file_button)
        self.output_layout.addWidget(self.output_file_edit)

        self.bottom_layout.addWidget(self.play_button)
        self.bottom_layout.addWidget(self.stop_button)
        self.bottom_layout.addWidget(self.record_button)
        self.bottom_layout.addLayout(self.volume_box)

        self.volume_box.addWidget(self.volume_label)
        self.volume_box.addWidget(self.volume_slider)

        self.layout.addWidget(self.video_widget)
        self.layout.addLayout(self.bottom_layout)
        self.layout.addWidget(self.seek_slider)
        self.layout.addLayout(self.input_layout)
        self.layout.addLayout(self.output_layout)

        # Personalizzazione della finestra
        self.setWindowTitle("Wish' Karaoke! :)")
        self.resize(800, 600)
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.bottom_layout.setContentsMargins(0, 0, 0, 0)
        self.widget.setLayout(self.layout)
        self.setCentralWidget(self.widget)

        self.setupMenus()
        self.setupUiConnections()

    def setupMenus(self):
        # setup the menus
        self.mainMenu = self.menuBar()

        # File menu and subitems
        self.fileMenu = self.mainMenu.addMenu('File')

        self.exitButton = QAction(self.exit_icon, 'Exit', self)
        self.exitButton.setShortcut('Ctrl+Q')
        self.exitButton.setStatusTip('Exit application')
        self.fileMenu.addAction(self.exitButton)

        # View menu and related items
        self.viewMenu = self.mainMenu.addMenu('View')

        # Fullscreen item
        self.toggleFullscreenButton = QAction(QIcon(""), 'Fullscreen', self)
        self.toggleFullscreenButton.setCheckable(True)
        self.toggleFullscreenButton.setStatusTip('Toggle fullscreen more')
        self.toggleFullscreenButton.setShortcut("CTRL+SHIFT+F")
        self.viewMenu.addAction(self.toggleFullscreenButton)

        # Tools menu and related items
        self.toolsMenu = self.mainMenu.addMenu('Tools')

        # Play/Rec bind toggle
        self.bindPlayRecButton = QAction(QIcon(""), 'Bind Play/Rec', self)
        self.bindPlayRecButton.setCheckable(True)
        self.bindPlayRecButton.setStatusTip('Bind Play and Rec')

        self.toolsMenu.addAction(self.bindPlayRecButton)

    def setupUiConnections(self):
        """
        Put all the UI connections and event catchers here, just to keep the code clean
        :return:
        """
        self.record_button.clicked.connect(self.recButtonState)
        self.seek_slider.sliderMoved.connect(self.media_player.setPosition)
        self.volume_slider.sliderMoved.connect(self.media_player.setVolume)
        self.media_player.positionChanged.connect(self.seek_slider.setValue)
        self.media_player.durationChanged.connect(
            partial(self.seek_slider.setRange, 0))
        self.play_button.clicked.connect(self.play_clicked)
        self.stop_button.clicked.connect(self.stop_clicked)
        self.media_player.stateChanged.connect(self.state_changed)
        #
        self.input_file_button.clicked.connect(self.selectInputFile)
        #
        self.input_file_edit.textChanged.connect(self.setInputMedia)
        #
        self.output_file_button.clicked.connect(self.selectOutputFile)
        self.output_file_edit.textChanged.connect(self.setOutputMedia)

        # menu connections
        # fullscreen
        self.toggleFullscreenButton.toggled.connect(self.toggleFullscreen)
        # quit
        self.exitButton.triggered.connect(self.close)
        # Play/Rec bind
        self.bindPlayRecButton.toggled.connect(self.bind_play_rec)

        # Installing event filter for the video widget
        self.video_widget.installEventFilter(self)

    def bind_play_rec(self):
        """
        toggle the binding between play and rec to start recording as soon as playback starts.


        :return: Nothing
        """
        if not self.bindPlayRecStatus:
            self.bindPlayRecStatus = True
        else:
            self.bindPlayRecStatus = False
        # If binding is active, the REC button is disabled.
        self.record_button.setDisabled(self.bindPlayRecStatus)

    def play_clicked(self):
        """
        Start or resume playback.
        If binding is active, start/pause the audio recording as well
        """
        if (self.media_player.state()
                in (QMediaPlayer.PausedState, QMediaPlayer.StoppedState)):
            self.media_player.play()
            logger.info("(Re)Starting playback")
            if self.bindPlayRecStatus:
                if (self.recorder.state() in (QAudioRecorder.PausedState,
                                              QAudioRecorder.StoppedState)):
                    logger.info(
                        "Rec/Play bind is on! (Re)Starting Recorder as well.")
                    self.recorder.record()
        else:
            self.media_player.pause()
            logger.info("Pausing playback")
            if self.bindPlayRecStatus:
                logger.info("Rec/Play bind is on! Pausing Recorder as well.")
                self.recorder.pause()

    def stop_clicked(self):
        """
        Stopping playback.
        if Play/Rec binding is on, stop also the recorder.
        """
        logger.info("Stopping playback")
        self.media_player.stop()
        if self.bindPlayRecStatus:
            logger.info("Rec/Play bind is on! Stopping Recorder as well.")
            self.recorder.stop()

    def state_changed(self, newstate):
        """
        Update buttons. Not really needed, probably.
        """
        states = {
            QMediaPlayer.PausedState: self.play_normal_icon,
            QMediaPlayer.PlayingState: self.pause_icon,
            QMediaPlayer.StoppedState: self.play_normal_icon
        }
        self.play_button.setIcon(states[newstate])
        # elegant way to enable/disable the stop button
        self.stop_button.setEnabled(newstate != QMediaPlayer.StoppedState)

    def eventFilter(self, obj, event):
        """
        Catch MouseButtonDblClick or CTRL+SHIFT+F to toggle fullscreen

        """
        if (event.type() == QEvent.KeyPress and event.modifiers() & Qt.ShiftModifier \
                    and event.modifiers() & Qt.ControlModifier and event.key() == 70) \
                    or event.type() == QEvent.MouseButtonDblClick:
            obj.setFullScreen(not obj.isFullScreen())
        return False

    def toggleFullscreen(self):
        self.video_widget.setFullScreen(not self.video_widget.isFullScreen())

    def selectInputFile(self):
        """
        Just a small function to open a file dialog
        """

        #self.input_file_edit.setText(QFileDialog.getOpenFileName())

        # encode the resulting filename as UNICODE text
        self.input_filename, _ = QFileDialog.getOpenFileName()
        self.input_file_edit.setText(self.input_filename)

    def setInputMedia(self, filename):
        self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))

    def selectOutputFile(self):
        """
        Just a small function to open a file dialog
        """
        self.output_filename, _ = QFileDialog.getSaveFileName()
        self.output_file_edit.setText(self.output_filename)

    def setOutputMedia(self, filename):
        self.recorder.setOutputLocation(QUrl.fromLocalFile(filename))

    def recButtonState(self):
        if self.record_button.isChecked():
            self.doRecord()
        else:
            self.stopRecord()

    def doRecord(self):
        """
        TODO: define this function better, toggled by the Rec button
        :return:
        """
        print("Recording")
        self.recorder.record()

    def stopRecord(self):
        print("Stopping recorder")
        self.recorder.stop()

    def setupConstants(self):
        self.rec_icon = QIcon.fromTheme("media-record", QIcon("icons/rec.png"))
        self.play_normal_icon = QIcon.fromTheme("media-playback-start",
                                                QIcon("icons/Play-Normal.png"))
        self.stop_normal_icon = QIcon.fromTheme("media-playback-stop",
                                                QIcon("icons/Stop-Normal.png"))
        self.exit_icon = QIcon.fromTheme("application-exit",
                                         QIcon("icons/application-exit.png"))
        self.pause_icon = QIcon.fromTheme(
            "media-playback-pause", QIcon("icons/Pause-Disabled-icon.png"))
        self.bindPlayRecStatus = False
Exemple #3
0
class Recorder(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)

        self.recorder = QAudioRecorder(self)
        self.recorder.stateChanged.connect(self.do_stateChanged)
        self.recorder.durationChanged.connect(self.do_durationChanged)

        self.probe = QAudioProbe(self)
        self.probe.setSource(self.recorder)
        self.probe.audioBufferProbed.connect(self.do_processBuffer)

        if self.recorder.defaultAudioInput() == "":  # str类型
            return  # 无音频录入设备

        for device in self.recorder.audioInputs():
            self.ui.comboDevices.addItem(device)  # 音频录入设备列表

        for codecName in self.recorder.supportedAudioCodecs():
            self.ui.comboCodec.addItem(codecName)  # 支持的音频编码

        sampleList, isContinuous = self.recorder.supportedAudioSampleRates()
        # isContinuous 是否支持连续的采样率,与C++不一样

        for i in range(len(sampleList)):
            self.ui.comboSampleRate.addItem("%d" % sampleList[i])  # 支持的采样率

# channels
        self.ui.comboChannels.addItem("1")
        self.ui.comboChannels.addItem("2")
        self.ui.comboChannels.addItem("4")

# quality
        self.ui.sliderQuality.setRange(0, QMultimedia.VeryHighQuality)
        self.ui.sliderQuality.setValue(QMultimedia.NormalQuality)

# bitrates
        self.ui.comboBitrate.addItem("32000")
        self.ui.comboBitrate.addItem("64000")
        self.ui.comboBitrate.addItem("96000")
        self.ui.comboBitrate.addItem("128000")

        self.__addToolbar()

    def __addToolbar(self):
        layout = QtWidgets.QVBoxLayout()

        Astart = QtWidgets.QToolButton()
        Astart.setText("开始")
        Astart.setDefaultAction(self.ui.actRecordStart)
        Apause = QtWidgets.QToolButton()
        Apause.setText("暂停")
        Apause.setDefaultAction(self.ui.actRecordPause)
        Astop = QtWidgets.QToolButton()
        Astop.setText("停止")
        Astop.setDefaultAction(self.ui.actRecordStop)

        self.toolbar = QtWidgets.QToolBar()
        self.toolbar.addWidget(Astart)
        self.toolbar.addWidget(Apause)
        self.toolbar.addWidget(Astop)

        layout.addWidget(self.toolbar)
        layout.addWidget(self.ui.widget)

        self.setLayout(layout)

    def __setRecordParams(self):
        selectedFile=self.ui.editOutputFile.text().strip()
        if (selectedFile ==""):
            QMessageBox.critical(self,"错误","请先设置录音输出文件")
            return False
        
        if os.path.exists(selectedFile):
            os.remove(selectedFile)#删除已有文件
                 
        recordFile=QUrl.fromLocalFile(selectedFile)
        self.recorder.setOutputLocation(recordFile)  #设置输出文件

        recordDevice=self.ui.comboDevices.currentText()
        self.recorder.setAudioInput(recordDevice)    #设置录入设备

        settings=QAudioEncoderSettings()    #音频编码设置
        settings.setCodec(self.ui.comboCodec.currentText())   #编码

        sampRate=int(self.ui.comboSampleRate.currentText())
        settings.setSampleRate(sampRate)    #采样率

        bitRate=int(self.ui.comboBitrate.currentText())
        settings.setBitRate(bitRate)  #比特率

        channelCount=int(self.ui.comboChannels.currentText())
        settings.setChannelCount(channelCount)    #通道数

        quality=QMultimedia.EncodingQuality(self.ui.sliderQuality.value())
        settings.setQuality(quality)     #品质

        if self.ui.radioQuality.isChecked():  #编码模式为固定品质,自动决定采样率,采样点大小
            settings.setEncodingMode(QMultimedia.ConstantQualityEncoding)
        else:
            settings.setEncodingMode(QMultimedia.ConstantBitRateEncoding)  #固定比特率
        
        self.recorder.setAudioSettings(settings) #音频设置
        return True

##  ==========由connectSlotsByName() 自动连接的槽函数==================    
    @pyqtSlot()
    def on_btnGetFile_clicked(self):    ##"录音输出文件"按钮
        curPath=os.getcwd()        #获取系统当前目录
        dlgTitle="选择输出文件"   
        filt="wav文件(*.wav)"     
        fileName,flt,=QFileDialog.getSaveFileName(self, dlgTitle, curPath, filt)
        if (fileName !=""):
            self.ui.editOutputFile.setText(fileName)
    
    @pyqtSlot()    ##开始录音
    def on_actRecordStart_triggered(self): 
        success=True
        if (self.recorder.state() == QMediaRecorder.StoppedState):  #已停止,重新设置
            success=self.__setRecordParams()  #设置录音参数
        if success:   
            self.recorder.record()

    @pyqtSlot()    ##暂停
    def on_actRecordPause_triggered(self): 
        self.recorder.pause()
    
    @pyqtSlot()
    def on_actRecordStop_triggered(self): 
        self.recorder.stop()

##  =============自定义槽函数===============================       
    def do_stateChanged(self,state):  ##状态变化
        isRecording=(state==QMediaRecorder.RecordingState)  #正在录制
        self.ui.actRecordStart.setEnabled(not isRecording)
        self.ui.actRecordPause.setEnabled(isRecording)
        self.ui.actRecordStop.setEnabled(isRecording)

        isStoped=(state==QMediaRecorder.StoppedState)    #已停止
        self.ui.btnGetFile.setEnabled(isStoped)
        self.ui.editOutputFile.setEnabled(isStoped)

    def do_durationChanged(self,duration):  ##持续时间长度变化
        self.ui.LabPassTime.setText("已录制 %d 秒"%(duration/1000))
    
    def do_processBuffer(self,buffer):     ##解析缓冲区数据
        self.ui.spin_byteCount.setValue(buffer.byteCount())      #缓冲区字节数
        self.ui.spin_duration.setValue(buffer.duration()/1000)   #缓冲区时长
        self.ui.spin_frameCount.setValue(buffer.frameCount())    #缓冲区帧数
        self.ui.spin_sampleCount.setValue(buffer.sampleCount())  #缓冲区采样数
  
        audioFormat=buffer.format()      #缓冲区格式,QAudioBuffer
        self.ui.spin_channelCount.setValue(audioFormat.channelCount()) #通道数
        self.ui.spin_sampleSize.setValue(audioFormat.sampleSize())     #采样大小
        self.ui.spin_sampleRate.setValue(audioFormat.sampleRate())     #采样率
        self.ui.spin_bytesPerFrame.setValue(audioFormat.bytesPerFrame()) #每帧字节数
  
        if (audioFormat.byteOrder()==QAudioFormat.LittleEndian):
           self.ui.edit_byteOrder.setText("LittleEndian")   #字节序
        else:
           self.ui.edit_byteOrder.setText("BigEndian")
  
        self.ui.edit_codec.setText(audioFormat.codec()) #编码格式
  
        if (audioFormat.sampleType()==QAudioFormat.SignedInt): #采样点类型
           self.ui.edit_sampleType.setText("SignedInt")
        elif(audioFormat.sampleType()==QAudioFormat.UnSignedInt):
           self.ui.edit_sampleType.setText("UnSignedInt")
        elif(audioFormat.sampleType()==QAudioFormat.Float):
           self.ui.edit_sampleType.setText("Float")
        else:
           self.ui.edit_sampleType.setText("Unknown")