UOS Python+Qt5实现声卡回路测试

1.回路治具设计:

2.Ui界面:

3.源代码:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'SoundTestWinFrm.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.

import json
import configparser
import subprocess
import sys
import os
import logging
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QFrame
from PyQt5.QtWidgets import QApplication, QListWidget, QListWidgetItem
from PyQt5.QtGui import QColor
from datetime import datetime
#from subprocess import Popen
import pyaudio
#import wave
import librosa #pip install pyaudio librosa
import numpy as np
import threading
import glob
from PyQt5.QtCore import QTimer, pyqtSignal
#import pygame #pip install pygame
#import alsaaudio #pip install pyalsaaudio pip install pyalsaaudio
#sudo apt-get install portaudio19-dev
#pip install pyaudio librosa
#import pulsectl #pip install pulsectl
#apt-get install sox

class AnalysisThread(QtCore.QThread):
    def __init__(self, filename,type, parent=None):
        super(AnalysisThread, self).__init__(parent)
        self.filename = filename
        self.type=type
        self.is_running = True

    def run(self):
        while self.is_running:
            # 在这里执行音频分析
            self.parent().AnalysisSoundFile_Frequency(self.filename,self.type)
            self.parent().standard_frequency=int(self.parent().AnalysisSound_FrequencySample)#标准的频响
            self.stop()

    def stop(self):
        self.is_running = False # 或者使用更安全的停止逻辑

class RecordPlayThread(QtCore.QThread):
    finished_signal = QtCore.pyqtSignal()  # 添加完成信号
    set_default_output_device_signal = QtCore.pyqtSignal(str)
    set_default_input_device_signal = QtCore.pyqtSignal(str)
    #analysisSoundFile_Frequency_signal=QtCore.pyqtSignal(str)

    def __init__(self,output_filename,input_filename,duration_seconds,indevice_name,outdevice_name, parent=None):
        super(RecordPlayThread, self).__init__(parent)
        self.output_filename=output_filename
        self.input_filename=input_filename
        self.duration_seconds=duration_seconds
        self.indevice_name=indevice_name
        self.outdevice_name=outdevice_name

        # 初始化其他变量
        if parent is not None:
            self.set_default_output_device_signal.connect(parent.set_default_output_device)
            self.set_default_input_device_signal.connect(parent.set_default_input_device)
            #self.analysisSoundFile_Frequency_signal.connect(parent.AnalysisSoundFile_Frequency)
        self.is_running = True

    def run(self):
        while self.is_running:# 执行录放音代码,确保在循环中频繁检查 self.is_running
            #执行设置默认音频设备并同步录放音
            # 发出信号而不是直接调用方法
            self.set_default_output_device_signal.emit(self.outdevice_name)
            self.set_default_input_device_signal.emit(self.indevice_name)
            # 录音线程
            record_thread = threading.Thread(target=self.parent().rec_record_audio, args=(self.input_filename, 2))
            # 播放线程
            play_thread = threading.Thread(target=self.parent().play_audio_for_duration, args=(self.output_filename, 2))
            # 启动线程
            record_thread.start()
            play_thread.start()
            # 等待线程完成
            record_thread.join()
            play_thread.join()
            #self.analysisSoundFile_Frequency_signal.emit(self.input_filename,1)
            self.parent().AnalysisSoundFile_Frequency(self.input_filename,1)#解析声响
            if self.parent().standard_frequency>=self.parent().AnalysisSound_FrequencySample-1 and \
                    self.parent().standard_frequency<=self.parent().AnalysisSound_FrequencySample+1:
                self.parent().tempTestPassItem+=2#测试接口两个
            self.finished_signal.emit()  # 线程完成时发射信号
            self.stop()

    def stop(self):
        self.is_running = False  # 或者使用更安全的停止逻辑

class Ui_Form(QWidget):
    updateTimer = pyqtSignal(bool)  # 定义一个信号

    def __init__(self):
        super().__init__()
        # ... 现有的初始化代码 ...
        self.analysis_threads = []  # 存储所有的 AnalysisThread 实例
        self.record_play_threads = []  # 存储所有的 RecordPlayThread 实例

        # 设置环境变量
        os.environ["XDG_RUNTIME_DIR"] = "/run/user/{}".format(os.getuid())
        self.config = configparser.ConfigParser()  # 创建对象
        self.itemName=''#项目名称
        self.itemFailSleepExit = 0  # 项目Fail延时退出
        self.testArgs = []  # 测试参数信息
        self.soundFile=[]#音频文件

        self.AnalysisSound_FrequencySample=0#解析的音频频率标准值
        self.Device_1AnalysisSound_Frequency=0#硬件设备1解析音频频率值
        self.Device_2AnalysisSound_Frequency=0#硬件设备2解析音频频率值
        self.output_devices=[]#输出音频设备名称
        self.input_devices=[]#输入音频设备名称
        self.in_output_devices=[]#输入输出设备名称

        self.readTestAudioDevice=[]#读取测试音频设备
        self.allAudioDeviceTestPass=[]#所有音频测试PASS设备
        self.front_Device=False
        self.rear_Device=False
        self.currentTestPort='front'#默认为前置

        self.testPortCount=0#测试端口总数
        self.ReadPortCount=0#读取的端口数
        self.standard_frequency=0#标准的频率
        self.tempTestPassItem=0#临时测试PASS项
        self.testPassItem=0#最终测试PASS项

        self.tempDeviceData=[]#临时的硬件信息
        self.testStandardArgs=''#测试标准参数

        # 生成日志信息
        self.logger = logging.getLogger('my_logger')  # 步骤1 创建日志记录器
        self.logger.setLevel(logging.DEBUG)  # 步骤2 将指定日志级别
        self.file_handler = logging.FileHandler('./log/log.txt')  # 步骤3 创建文件处理器
        self.formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')  # 步骤4 创建格式化器
        self.file_handler.setFormatter(self.formatter)  # 步骤4 将格式化器添加到处理器
        self.logger.addHandler(self.file_handler)  # 步骤5 将处理器添加到日志记录器

        # 读取配置
        self.config.read('./Conf/config.conf', encoding='utf-8')  # 读取配置文件,如果配置文件不存在则创建

        # 读取测试配置
        self.itemName = self.config.get('TestItemNameArrays', 'SoundTestName')
        self.itemFailSleepExit = int(self.config.get('TestItemWinFrmSleepExit', 'SoundTestName'))  # 项目测试Fail延时退出
        self.testArgs = self.ReadJsonInfo('./Conf/TestArgs.json')  # 读取测试参数信息

        self.disable_hdmi_audio()  # 禁用HDMI

        #读取标准值
        if self.ReadJsonTestArgs(self.itemName)==True:
            self.ReadPortCount=int(self.testStandardArgs)#读取测试参数
            #读取音频文件
            self.soundFile.append('./'+self.config.get('SoundHd','F_L'))#高音左声道
            self.soundFile.append('./'+self.config.get('SoundHd','F_R'))#高音左声道
            self.soundFile.append('./'+self.config.get('SoundHd','M_L'))#中音左声道
            self.soundFile.append('./'+self.config.get('SoundHd','M_R'))#中音右声道
            self.soundFile.append('./'+self.config.get('SoundHd','S_L'))#低音左声道
            self.soundFile.append('./'+self.config.get('SoundHd','S_R'))#低音右声道
            self.soundFile.append('./'+self.config.get('SoundHd', 'Audio'))  # 低音右声道

            self.setupUi()
            if self.GetTestPortCount()==True:
                self.InfoListAddData(f'读取音频:{str(self.testPortCount)}.个端口-实际配置端口:{self.ReadPortCount}', 1)
                self.lbl_MesInfo.setText('标准音频文件频率解析中...')
                self.delete_wav_files('.')#删除目录生成的所有音频文件
                #self.list_audio_devices()#列出所有音频输入设备
                #self.list_record_devices()#列出所有音频输出设备

                #解析声响频率
                self.start_analysis_threads()

                #读取音频设备
                #self.list_audio_devices_list()

                # 获取音频设备名称
                # 获取音频输出和输入设备名称
                #self.RecordPlay_analysis_threads()#自动测试音频

                #解析躁声
                #self.AnalysisSoundFile_Noise(self.soundFile[6])
                #self.AnalysisSoundFile_Noise(self.soundFile[3])
                #self.AnalysisSoundFile_Noise(self.soundFile[2])

                # 创建一个定时器来检查视频是否播放结束
                self.timer_1 = QTimer(self)
                self.timer_1.setInterval(1000)  # 每秒检查一次
                self.timer_1.timeout.connect(self.check_Test)
                self.timer_1.start()

                # 连接信号到槽
                self.updateTimer.connect(self.handleTimer)
            else:
                self.InfoListAddData(f'读取音频:{str(self.testPortCount)}.个端口-实际配置端口:{self.ReadPortCount}', 3)

    # 定义触发器
    def handleTimer(self, start):
        if start:
            self.timer_1.start()
        else:
            self.timer_1.stop()

    #校验是否完成测试
    def check_Test(self):
        try:
            if self.testPassItem>=int(self.ReadPortCount):#判断是否PASS
                self.UpdateJsonTestArgs(self.itemName,'PASS')
                sys.exit(0)
            else:
                self.updateTimer.emit(False)  # 发射信号以停止定时器
                self.RecordPlay_analysis_threads()
        except Exception as e:
            self.ShowLog(f"check_Test Err:{e}", False)
            self.InfoListAddData(f"check_Test Err:{str(e)}",3)
            return False


    # 检测当前测试设备并进行判断
    def DetectsTheCurrentTestDevice(self):
        try:
            #运行命令并获取输出
            process=subprocess.Popen('pactl list cards | grep "available"',stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True, encoding='utf-8')
            #逐行读取输出
            self.readTestAudioDevice.clear()#清空列表
            while True:
                output=process.stdout.readline()
                if output=='' and process.poll() is not None:
                    break
                if  output not in self.readTestAudioDevice:
                    if 'hdmi' not in output.lower() and 'not available' not in output.lower() and 'input-linein' not in output.lower():
                        portinfo = output.strip()[:output.find(':')]
                        if self.front_Device==True:#前置音频测试PASS
                            if 'front' in portinfo.lower():
                                return False
                            else:
                                self.readTestAudioDevice.append(portinfo)
                        elif self.rear_Device==True:#后置音频测试PASS
                            if 'rear' in portinfo.lower():
                                return False
                            else:
                                self.readTestAudioDevice.append(portinfo)
                        else:
                            self.readTestAudioDevice.append(portinfo)
            if 'rear' in str(self.readTestAudioDevice) and len(self.readTestAudioDevice)==2:#判断当前为后置接口
                print('rear',len(self.readTestAudioDevice))
                self.currentTestPort = 'rear'
                self.label_2.setStyleSheet('')  # 前置端口背景颜色设置为默认透明
                self.label_3.setStyleSheet("background-color: lightgreen;")  # 后置端口背景色设置为浅绿色
                self.lbl_MesInfo.setText('后置音频接口测试')
                return True
            elif 'front' in str(self.readTestAudioDevice) and len(self.readTestAudioDevice)==2:#判断当前为前置接口
                print('front', len(self.readTestAudioDevice))
                self.currentTestPort = 'front'
                self.label_2.setStyleSheet('background-color: lightgreen;')  # 前置端口背景颜色设置为浅绿色
                self.label_3.setStyleSheet("")  # 后置端口背景色设置默认透明
                self.lbl_MesInfo.setText('前置音频接口测试')
                return True
            return False
        except Exception as e:
            self.ShowLog(f"DetectsTheCurrentTestDevice Err:{e}", False)
            self.InfoListAddData(f"DetectsTheCurrentTestDevice Err:{str(e)}",3)
            return False


    #获取当前产测试端口测试
    def GetTestPortCount(self):
        try:
            # 运行命令并获取输出
            process = subprocess.Popen('pactl list cards | grep "available"', stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True, encoding='utf-8')
            # 逐行读取输出
            while True:
                output=process.stdout.readline()
                if output=='' and process.poll() is not None:
                    break
                if  'hdmi' not in output.lower():
                    self.testPortCount+=1
            #print(self.ReadPortCount,self.testPortCount)
            if int(self.ReadPortCount)==self.testPortCount:
                return True
            else:
                return False
        except Exception as e:
            self.ShowLog(f"GetTestPortCount Err:{e}", False)
            self.InfoListAddData(f"GetTestPortCount Err:{str(e)}",3)
            return False

    # 启动多线程
    def RecordPlay_analysis_threads(self):
        try:
            self.lbl_MesInfo.setText('音频接口检测中...')
            # 创建多个线程
            self.threads = []
            if self.DetectsTheCurrentTestDevice() == True:#判断当前设置是否接入有效,确认是前置还是后置
            #if self.get_audio_devices()==True:#获取音频输入输出端口信息
                self.lbl_MesInfo.setText('获取音频端口信息..')
                self.AnalysisSound_FrequencySample=0  # 清空高音信息
                self.evice_1AnalysisSound_Frequency=0  # 清空中音信息
                self.Device_2AnalysisSound_Frequency=0  # 清空低音信息
                self.tempTestPassItem=0
                if self.get_audio_devices() == True:  # 获取音频输入输出端口信息
                #if self.DetectsTheCurrentTestDevice() == True:
                    x=0
                    y=0
                    if len(self.output_devices)>1:
                        x=1
                    if len(self.input_devices)>1:
                        y=1
                    if self.currentTestPort=='front':#前置测试
                        thread = RecordPlayThread(self.soundFile[6], 'sample_1.wav', 2, self.input_devices[y],self.output_devices[x], self)  # 注意这里传递了 self 作为 parent
                        thread.finished_signal.connect(self.on_thread_finished)  # 连接信号
                        self.threads.append(thread)
                        self.record_play_threads.append(thread)
                        thread.start()

                    elif self.currentTestPort=='rear':#后置测试
                        thread = RecordPlayThread(self.soundFile[6], 'sample_1.wav', 2, self.input_devices[y],self.output_devices[x], self)  # 注意这里传递了 self 作为 parent
                        thread.finished_signal.connect(self.on_thread_finished)  # 连接信号
                        self.threads.append(thread)
                        self.record_play_threads.append(thread)
                        thread.start()
                else:
                    self.updateTimer.emit(True)  # 启动时钟
            else:
                self.updateTimer.emit(True)  # 启动时钟
        except Exception as e:
            self.ShowLog(f"RecordPlay_analysis_threads Err:{e}", False)
            self.InfoListAddData(f"RecordPlay_analysis_threads Err:{str(e)}", 3)
            return False

    # 检查所有线程是否完成
    def on_thread_finished(self):

        if all(not thread.isRunning() for thread in self.threads):
            self.handle_all_threads_finished()

    # 所有线程完成后执行的代码
    def handle_all_threads_finished(self):
        if self.currentTestPort == 'front' and self.tempTestPassItem == 2:  # 前置测试
            self.testPassItem += 2
            self.front_Device = True
            self.InfoListAddData(f'测试完成的音频接口信息:inputPort-{self.input_devices[0]},outputPort-{self.output_devices[0]}',1)
            self.InfoListAddData(f'当前测试PASS音频:{self.testPassItem}.个端口', 2)
            self.lbl_Front_Out_Port.setText('PASS')
            self.lbl_Front_In_Port.setText('PASS')
            self.lbl_Front_Out_Port.setStyleSheet('color:green;')
            self.lbl_Front_In_Port.setStyleSheet('color:green;')
        elif self.currentTestPort == 'rear' and self.tempTestPassItem >= 2:  # 后置
            self.testPassItem += 3
            self.rear_Device = True
            self.InfoListAddData(f'测试完成的音频接口信息:inputPort-{self.input_devices[0]},outputPort-{self.output_devices[0]}', 1)
            self.InfoListAddData(f'当前测试PASS音频:{self.testPassItem}.个端口', 2)
            self.lbl_Rear_Out_Port.setText('PASS')
            self.lbl_Rear_In_Port.setText('PASS')
            self.lbl_Rear_Out_Port.setStyleSheet('color:green;')
            self.lbl_Rear_In_Port.setStyleSheet('color:green;')
        else:
            if self.currentTestPort == 'front':
                self.lbl_Front_Out_Port.setText('FAIL')
                self.lbl_Front_In_Port.setText('FAIL')
                self.lbl_Front_Out_Port.setStyleSheet('color:red;')
                self.lbl_Front_In_Port.setStyleSheet('color:red;')
            else:
                self.lbl_Rear_Out_Port.setText('FAIL')
                self.lbl_Rear_In_Port.setText('FAIL')
                self.lbl_Rear_Out_Port.setStyleSheet('color:red;')
                self.lbl_Rear_In_Port.setStyleSheet('color:red;')
        self.updateTimer.emit(True)  # 启动时钟

   # rec音频录制
    def rec_record_audio(self,output_filename, duration_seconds):
        try:
            # 调用rec命令录制音频
            # 检查文件是否存在
            if os.path.exists(output_filename):
                # 删除文件
                os.remove(output_filename)
            self.InfoListAddData(f'音频录入--------------{output_filename}',1)
            subprocess.run(['rec', output_filename,'trim','0', str(duration_seconds)], check=True)
            print(f"Audio recorded to {output_filename}")
        except subprocess.CalledProcessError as e:
            print(f"Error recording audio: {e}")

    #play 音频播放
    def play_audio_for_duration(self,input_filename, duration_seconds):
        try:
            # 使用play命令和trim效果播放特定时长的音频
            self.InfoListAddData(f'音频播放--------------{input_filename}', 1)
            subprocess.run(['play', input_filename, 'trim', '0', str(duration_seconds)], check=True)
            print(f"Played {duration_seconds} seconds of {input_filename}")
        except subprocess.CalledProcessError as e:
            print(f"Error playing audio: {e}")

    #获取接入音频装置名称
    def get_audio_devices(self,exclude_keyword='hdmi'):
        try:
            #self.tempDeviceData.clear()#清空临时数据
            self.input_devices.clear()#清空临时数据
            self.output_devices.clear()#清空临时数据
            # 获取输出设备
            result_sinks = subprocess.run(['pactl', 'list', 'short', 'sinks'], capture_output=True, text=True,check=True)
            # 获取输入设备
            result_sources = subprocess.run(['pactl', 'list', 'short', 'sources'], capture_output=True, text=True,check=True)
            # 解析输出和输入设备名称
            def parse_device_names(self,output,portType):
                device_names = []
                #print(output.split('\n'))
                for line in output.split('\n'):
                    parts = line.split('\t')
                    if len(parts) > 1:
                        device_name = parts[1]
                        # 排除指定关键词(如HDMI)的设备cle
                        #if device_name not in self.in_output_devices:
                        if exclude_keyword.lower() not in device_name.lower():
                            if 'sources' in portType.lower():#输入
                                if 'input' in device_name.lower():
                                    device_names.append(device_name)
                            elif 'sources' not in portType.lower():#输出
                                device_names.append(device_name)
                return device_names
            self.output_devices = parse_device_names(self,result_sinks.stdout,'output')
            self.input_devices = parse_device_names(self,result_sources.stdout,'input')

            #判断当前输入设备为前置|后置
            print('self.currentTestPort=',self.currentTestPort,'\nself.output_devices=',self.output_devices,'\nself.output_devices=',self.input_devices)
            if self.currentTestPort=='front' and len(self.output_devices)>0 and len(self.input_devices)>0:#判断前置
                return True
            elif self.currentTestPort=='rear' and len(self.output_devices)>0 and len(self.input_devices)>1:#判断后置
                return True
                #self.InfoListAddData(f'音频输出端口信息:{self.output_devices}', 1)
                #self.InfoListAddData(f'音频输入端口信息:{self.input_devices}', 1)
            else:
                return False
        except subprocess.CalledProcessError as e:
            print(f"Error: {e}")
            return False

    #禁用HDMI音频输出
    def disable_hdmi_audio(self):
        try:
            # 获取所有 sinks 的列表
            result = subprocess.run(['pactl', 'list', 'short', 'sinks'], capture_output=True, text=True, check=True)
            lines = result.stdout.split('\n')

            # 查找 HDMI 设备
            hdmi_sink = None
            for line in lines:
                if 'hdmi' in line.lower():
                    hdmi_sink = line.split('\t')[1]
                    break

            # 禁用找到的 HDMI 设备
            if hdmi_sink:
                subprocess.run(['pactl', 'set-sink-mute', hdmi_sink, '1'], check=True)
                print("HDMI audio output has been disabled.")
            else:
                print("No HDMI audio output found.")

        except subprocess.CalledProcessError as e:
            print(f"Error disabling HDMI audio output: {e}")

    #启动HDMI音频输出
    def enable_hdmi_audio(self):
        try:
            # 获取所有 sinks 的列表
            result = subprocess.run(['pactl', 'list', 'short', 'sinks'], capture_output=True, text=True, check=True)
            lines = result.stdout.split('\n')

            # 查找 HDMI 设备
            hdmi_sink = None
            for line in lines:
                if 'hdmi' in line.lower():
                    hdmi_sink = line.split('\t')[1]
                    break

            # 启动找到的 HDMI 设备
            if hdmi_sink:
                subprocess.run(['pactl', 'set-sink-mute', hdmi_sink, '0'], check=True)
                print("HDMI audio output has been enabled.")
            else:
                print("No HDMI audio output found.")

        except subprocess.CalledProcessError as e:
            print(f"Error disabling HDMI audio output: {e}")

    #设置为默认output音频设备
    def set_default_output_device(self,device_name):
        try:
            # 设置默认的输出设备
            subprocess.run(['pactl', 'set-default-sink', device_name], check=True)#设置默认音频接口
            subprocess.run(['pactl', 'set-sink-volume', device_name, '80%'], check=True)#设置音量
            print(f"Default output device set to: {device_name}")
        except subprocess.CalledProcessError as e:
            print(f"Error setting default output device: {e}")

    # 设置为默认input音频设备
    #sox
    def set_default_input_device(self,device_name):
        try:
            # 设置默认的输入设备
            subprocess.run(['pactl', 'set-default-source', device_name], check=True)
            subprocess.run(['pactl', 'set-source-volume', device_name, '80%'], check=True)  # 设置音量
            print(f"Default input device set to: {device_name}")
        except subprocess.CalledProcessError as e:
            print(f"Error setting default input device: {e}")

    #启动多线程
    def start_analysis_threads(self):
        # 创建多个线程
        self.threads = []
        #for file in [self.soundFile[6], self.soundFile[3], self.soundFile[2]]:
        for file in [self.soundFile[6]]:
            thread = AnalysisThread(file,1, self)
            thread.start()
            self.threads.append(thread)
            self.analysis_threads.append(thread)

    #删除当前目录下所有*.wav文件
    def delete_wav_files(self,directory):
        # 构造当前目录中所有.wav文件的路径模式
        path_pattern = os.path.join(directory, '*.wav')

        # 使用glob模块找到所有匹配的文件
        wav_files = glob.glob(path_pattern)

        # 遍历所有找到的.wav文件并删除它们
        for file_path in wav_files:
            try:
                os.remove(file_path)
                print(f"Deleted: {file_path}")
            except Exception as e:
                print(f"Error deleting {file_path}: {e}")

    def synchronized_play_record(self,playback_file, record_duration, record_file, playback_device, record_device):
        # Create threads for playback and recording
        playback_thread = threading.Thread(target=self.play_audio, args=(playback_file, playback_device))
        recording_thread = threading.Thread(target=self.record_audio, args=(record_duration, record_file, record_device))

        # Start both threads
        playback_thread.start()
        recording_thread.start()

        # Wait for both threads to complete
        playback_thread.join()
        recording_thread.join()


    #读取音频设备
    def list_audio_devices_list(self):
        try:
            p = pyaudio.PyAudio()
            print("Available audio devices:")
            for index in range(p.get_device_count()):
                device_info = p.get_device_info_by_index(index)
                device_name = device_info.get('name')
                input_channels = device_info.get('maxInputChannels')
                output_channels = device_info.get('maxOutputChannels')

                if input_channels > 0:
                    if 'HDMI' not in device_name and 'hdmi' not in device_name:
                        #print(f"Recording Device: {device_name} (Index: {index}, Input Channels: {input_channels})")
                        self.InfoListAddData(f"Recording Device: {device_name} (Index: {index}, Input Channels: {input_channels})",1)
                        self.Playback_deviceIndx.append(index)#音频播放


                if output_channels > 0:
                    if 'HDMI' not in device_name and 'hdmi' not in device_name:
                        #print(f"Playback Device: {device_name} (Index: {index}, Output Channels: {output_channels})")
                        self.InfoListAddData(f"Recording Device: {device_name} (Index: {index}, Input Channels: {input_channels})", 1)
                        self.Record_deviceIndx.append(index)#音频录音

            p.terminate()
        except Exception as e:
            self.ShowLog("AnalysisSoundFile_Frequency Err:" + str(e), False)
            self.InfoListAddData(f"AnalysisSoundFile_Frequency Err:{str(e)}",3)


    def setupUi(self):
        self.setObjectName("Form")
        self.resize(1000, 940)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("IMAGE/Sound.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.setWindowIcon(icon)
        self.gridLayout_2 = QtWidgets.QGridLayout(self)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout()
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.lbl_logo = QtWidgets.QLabel(self)
        self.lbl_logo.setText("")
        self.lbl_logo.setPixmap(QtGui.QPixmap("IMAGE/logo.jpg"))
        self.lbl_logo.setObjectName("lbl_logo")
        self.verticalLayout_4.addWidget(self.lbl_logo)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.lbl_MesInfo = QtWidgets.QLabel(self)
        self.lbl_MesInfo.setFont(font)
        self.lbl_MesInfo.setStyleSheet("background-color: rgb(170, 255, 127);")
        self.lbl_MesInfo.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_MesInfo.setObjectName("lbl_MesInfo")
        self.verticalLayout_4.addWidget(self.lbl_MesInfo)
        self.horizontalLayout.addLayout(self.verticalLayout_4)
        self.verticalLayout_5 = QtWidgets.QVBoxLayout()
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.label_12 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(False)
        font.setWeight(50)
        self.label_12.setFont(font)
        self.label_12.setStyleSheet("background-color: rgb(170, 170, 127);")
        self.label_12.setText("项目名称")
        self.label_12.setAlignment(QtCore.Qt.AlignCenter)
        self.label_12.setObjectName("label_12")
        self.verticalLayout_5.addWidget(self.label_12)
        self.verticalLayout_10 = QtWidgets.QVBoxLayout()
        self.verticalLayout_10.setObjectName("verticalLayout_10")
        self.label_13 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_13.setFont(font)
        self.label_13.setStyleSheet("background-color: rgb(255, 170, 127);")
        self.label_13.setText("端口信息")
        self.label_13.setAlignment(QtCore.Qt.AlignCenter)
        self.label_13.setObjectName("label_13")
        self.verticalLayout_10.addWidget(self.label_13)
        self.label_14 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_14.setFont(font)
        self.label_14.setStyleSheet("background-color: rgb(0, 255, 127);")
        self.label_14.setText("测试结果")
        self.label_14.setAlignment(QtCore.Qt.AlignCenter)
        self.label_14.setObjectName("label_14")
        self.verticalLayout_10.addWidget(self.label_14)
        self.verticalLayout_5.addLayout(self.verticalLayout_10)
        self.horizontalLayout.addLayout(self.verticalLayout_5)
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.label_2 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setFamily("微软雅黑")
        font.setPointSize(16)
        font.setBold(False)
        font.setWeight(50)
        self.label_2.setFont(font)
        self.label_2.setStyleSheet("")
        self.label_2.setText("前置")
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.verticalLayout_3.addWidget(self.label_2)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout()
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.label_5 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_5.setFont(font)
        self.label_5.setAlignment(QtCore.Qt.AlignCenter)
        self.label_5.setObjectName("label_5")
        self.verticalLayout_6.addWidget(self.label_5)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.lbl_Front_Out_Port = QtWidgets.QLabel(self)
        self.lbl_Front_Out_Port.setFont(font)
        self.lbl_Front_Out_Port.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_Front_Out_Port.setObjectName("lbl_Front_Out_Port")
        self.verticalLayout_6.addWidget(self.lbl_Front_Out_Port)
        self.horizontalLayout_3.addLayout(self.verticalLayout_6)
        self.verticalLayout_7 = QtWidgets.QVBoxLayout()
        self.verticalLayout_7.setObjectName("verticalLayout_7")
        self.label_6 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_6.setFont(font)
        self.label_6.setAlignment(QtCore.Qt.AlignCenter)
        self.label_6.setObjectName("label_6")
        self.verticalLayout_7.addWidget(self.label_6)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.lbl_Front_In_Port = QtWidgets.QLabel(self)
        self.lbl_Front_In_Port.setFont(font)
        self.lbl_Front_In_Port.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_Front_In_Port.setObjectName("lbl_Front_In_Port")
        self.verticalLayout_7.addWidget(self.lbl_Front_In_Port)
        self.horizontalLayout_3.addLayout(self.verticalLayout_7)
        self.verticalLayout_3.addLayout(self.horizontalLayout_3)
        self.horizontalLayout.addLayout(self.verticalLayout_3)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label_3 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setFamily("微软雅黑")
        font.setPointSize(16)
        font.setBold(False)
        font.setWeight(50)
        self.label_3.setFont(font)
        self.label_3.setStyleSheet("")
        self.label_3.setText("后置")
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        self.verticalLayout_2.addWidget(self.label_3)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.verticalLayout_8 = QtWidgets.QVBoxLayout()
        self.verticalLayout_8.setObjectName("verticalLayout_8")
        self.label_8 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_8.setFont(font)
        self.label_8.setAlignment(QtCore.Qt.AlignCenter)
        self.label_8.setObjectName("label_8")
        self.verticalLayout_8.addWidget(self.label_8)
        self.lbl_Rear_Out_Port = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.lbl_Rear_Out_Port.setFont(font)
        self.lbl_Rear_Out_Port.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_Rear_Out_Port.setObjectName("lbl_Rear_Out_Port")
        self.verticalLayout_8.addWidget(self.lbl_Rear_Out_Port)
        self.horizontalLayout_4.addLayout(self.verticalLayout_8)
        self.verticalLayout_9 = QtWidgets.QVBoxLayout()
        self.verticalLayout_9.setObjectName("verticalLayout_9")
        self.label_10 = QtWidgets.QLabel(self)
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(False)
        font.setWeight(50)
        self.label_10.setFont(font)
        self.label_10.setAlignment(QtCore.Qt.AlignCenter)
        self.label_10.setObjectName("label_10")
        self.verticalLayout_9.addWidget(self.label_10)
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(False)
        font.setWeight(50)
        self.lbl_Rear_In_Port = QtWidgets.QLabel(self)
        self.lbl_Rear_In_Port.setFont(font)
        self.lbl_Rear_In_Port.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_Rear_In_Port.setObjectName("lbl_Rear_In_Port")
        self.verticalLayout_9.addWidget(self.lbl_Rear_In_Port)
        self.horizontalLayout_4.addLayout(self.verticalLayout_9)
        self.verticalLayout_2.addLayout(self.horizontalLayout_4)
        self.horizontalLayout.addLayout(self.verticalLayout_2)
        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.groupBox = QtWidgets.QGroupBox(self)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout_3.setObjectName("gridLayout_3")
        font = QtGui.QFont()
        font.setPointSize(12)
        self.ltwgt_Log = QtWidgets.QListWidget(self.groupBox)
        self.ltwgt_Log.setObjectName("ltwgt_Log")
        self.ltwgt_Log.setFont(font)
        self.gridLayout_3.addWidget(self.ltwgt_Log, 0, 0, 1, 1)
        self.horizontalLayout_2.addWidget(self.groupBox)
        self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
        self.lbl_Result_Log = QtWidgets.QLabel(self)
        self.lbl_Result_Log.setStyleSheet("background-color: rgb(0, 0, 0);")
        self.lbl_Result_Log.setText("")
        self.lbl_Result_Log.setAlignment(QtCore.Qt.AlignCenter)
        self.lbl_Result_Log.setObjectName("lbl_Result_Log")
        self.gridLayout.addWidget(self.lbl_Result_Log, 2, 0, 1, 1)
        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)

        self.retranslateUi()
        QtCore.QMetaObject.connectSlotsByName(self)
        self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowCloseButtonHint)  # 只显示最小化按钮和关闭按钮

    def retranslateUi(self):
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Form", "Sound_HD"))
        self.lbl_MesInfo.setText(_translate("Form", "当前前置Out_Port测试中.."))
        self.label_5.setText(_translate("Form", "OUT_PORT"))
        self.lbl_Front_Out_Port.setText(_translate("Form", "N/A"))
        self.label_6.setText(_translate("Form", "IN_PORT"))
        self.lbl_Front_In_Port.setText(_translate("Form", "N/A"))
        self.label_8.setText(_translate("Form", "OUT_PORT"))
        self.lbl_Rear_Out_Port.setText(_translate("Form", "N/A"))
        self.label_10.setText(_translate("Form", "IN_PORT"))
        self.lbl_Rear_In_Port.setText(_translate("Form", "N/A"))
        #self.groupBox.setTitle(_translate("Form", "-日志"))

    #列出所有录音设备
    def list_audio_devices(self):
        try:
            #result = subprocess.run(['arecord', '-l'], capture_output=True, text=True)
            readcmdinfo=subprocess.check_output(['arecord', '-l'], stderr=subprocess.STDOUT)
            lines = readcmdinfo.decode('utf-8').split('\n')
            i=0
            for recordinfo in lines:
                if 'card' in recordinfo:
                    self.CaptuerHardwareDevices.append(recordinfo)#添加录音设备信息
                    card=recordinfo[recordinfo.find('card')+5:recordinfo.find('card')+6]
                    device=recordinfo[recordinfo.find('device')+7:recordinfo.find('device')+8]
                    self.Recordhw.append('hw:'+card+','+device)
                    if i==0:
                        self.lbl_Front_In_Port.setText('hw:'+card+','+device)
                    elif i==1:
                        self.lbl_Rear_In_Port.setText('hw:'+card+','+device)
                    self.InfoListAddData(recordinfo, 1)
                    i+=1

        except Exception as e:
            self.ShowLog("list audio devices Info Err:" + str(e), False)
            sys.exit(1)

    #列出所有放音设备
    def list_record_devices(self):
        try:
            #result=subprocess.run(['aplay','-l'], capture_output=True, text=True)
            readcmdinfo = subprocess.check_output(['aplay','-l'], stderr=subprocess.STDOUT)
            lines = readcmdinfo.decode('utf-8').split('\n')
            for playback in lines:
                if 'card' in playback and 'HDMI' not in playback:
                    self.PlaybackHardwareDevices.append(playback)#添加音频播放设备信息
                    card=playback[playback.find('card')+5:playback.find('card')+6]
                    device=playback[playback.find('device')+7:playback.find('device')+8]
                    self.Playbackhw.append('hw:'+card+','+device)
                    if len(self.Recordhw)>1:
                        self.lbl_Front_Out_Port.setText('hw:'+card+','+device)
                        self.lbl_Rear_Out_Port.setText('hw:'+card+','+device)
                    else:
                        self.lbl_Front_Out_Port.setText('hw:' + card + ',' + device)
                    self.InfoListAddData(playback,1)
        except Exception as e:
            self.ShowLog("list record devices Info Err:" + str(e), False)
            sys.exit(1)

    #messtr:信息字符串 infoType:信息类型 1=提示信息,2=测试PASS信息,3=测试FAIL信息
    def InfoListAddData(self,messtr,infoType):
        try:
            # 获取当前时间
            current_time = datetime.now()
            # 提取年月日时分秒
            year = current_time.year
            month = current_time.month
            day = current_time.day
            hour = current_time.hour
            minute = current_time.minute
            second = current_time.second

            item = QListWidgetItem(messtr)
            if infoType==1:
                item.setForeground(QColor("blue"))
            elif infoType==2:
                item.setForeground(QColor("green"))
            elif infoType==3:
                item.setForeground(QColor("red"))
            #self.ltwgt_Log.addItem(year+'-'+month+'-'+day+' '+hour+':'+minute+':'+second+' '+item)
            self.ltwgt_Log.addItem(item)
            self.ltwgt_Log.setEnabled(False)#只读
            # 将光标移动到最底部
            self.ltwgt_Log.scrollToBottom()
        except Exception as e:
            self.ShowLog("InfoListAddData Err:" + str(e), False)
            sys.exit(1)

    #窗口关闭
    def closeEvent(self, event):
        # 停止所有 AnalysisThread 实例
        for thread in self.analysis_threads:
            thread.stop()
            thread.wait()

        # 停止所有 RecordPlayThread 实例
        for thread in self.record_play_threads:
            thread.stop()
            thread.wait()
        self.UpdateJsonTestArgs(self.itemName,'FAIL')
        self.enable_hdmi_audio()#启动hdmi
        sys.exit(1)

    # 定义一个函数使得函数窗口居中显示
    def Center(self):
        # 获取屏幕尺寸
        screen_geometry = app.desktop().availableGeometry()
        # 计算窗口居中位置
        x = (screen_geometry.width() - self.width()) // 2
        y = (screen_geometry.height() - self.height()) // 2
        # 设置窗口位置
        self.move(x, y)

    # 读取项目参数信息,itemName:项目名称
    def ReadJsonTestArgs(self, itemName):
        try:
            self.testArgs = self.ReadJsonInfo('./Conf/TestArgs.json')
            for js in self.testArgs:
                if itemName in js['ItemName']:
                    self.testStandardArgs = js['Standard']
                    return True
            self.ShowLog('Read TestArgs.json ItemName:' + itemName + ' Info Is Empty!!', False)
            sys.exit(1)
        except Exception as e:
            self.ShowLog("Read TestArgs.json ItemName:" + itemName + " Info Err:" + str(e), False)
            sys.exit(1)

    #更新测试参数json,itemName:项目名称,readValue:读取值,testResult:测试结果
    def UpdateJsonTestArgs(self,itemName,testResult):
        try:
            updateTestArgs=[]#更新的测试参数
            self.testArgs=self.ReadJsonInfo('./Conf/TestArgs.json')
            for js in self.testArgs:
                if itemName in js['ItemName']:
                    #js['Read']=readValue#读取的值
                    js['TestResult']=testResult#测试结果
                    updateTestArgs.append(js)
                else:
                    updateTestArgs.append(js)
            with open("./Conf/TestArgs.json", "w") as write_file:
                json.dump(updateTestArgs, write_file)
            return True
        except Exception as e:
            self.ShowLog("Read TestArgs.json ItemName:"+itemName+" Info Err:" + str(e),False)
            sys.exit(1)

    #解析音频文件声响频率 fileName:文件名称,type:类型 1:标准值,2:接口1读取的值 3:接口2读取的值
    def AnalysisSoundFile_Frequency(self,fileNme,type):
        try:
            # 加载音频文件
            audio_path = fileNme
            y, sr = librosa.load(audio_path)

            # 获取频率和时间
            fft = np.fft.fft(y)
            magnitude = np.abs(fft)
            frequency = np.linspace(0, sr, len(magnitude))

            # 只获取左侧频谱,因为右侧是对称的
            left_frequency = frequency[:int(len(frequency) / 2)]
            left_magnitude = magnitude[:int(len(frequency) / 2)]

            # 找到最大幅度的频率
            max_magnitude = np.argmax(left_magnitude)
            peak_freq = left_frequency[max_magnitude]

            #print(f"{fileNme} Peak Frequency: {peak_freq} Hz")

            if type==1:
                self.AnalysisSound_FrequencySample=int(peak_freq)
                self.InfoListAddData(f"Sample {fileNme} Peak Frequency: {peak_freq} Hz", 1)
            elif type==2:
                self.Device_1AnalysisSound_Frequency=int(peak_freq)
                self.InfoListAddData(f"Recordhw-{self.Recordhw[0]}-Playbackhw:{self.Playbackhw[0]} {fileNme} Peak Frequency: {peak_freq} Hz", 1)
            elif type==3:
                self.Device_2AnalysisSound_Frequency=int(peak_freq)
                self.InfoListAddData(f"Recordhw-{self.Recordhw[0]}-Playbackhw:{self.Playbackhw[0]} {fileNme} Peak Frequency: {peak_freq} Hz",1)
        except Exception as e:
            self.ShowLog("AnalysisSoundFile_Frequency Err:" + str(e), False)
            self.InfoListAddData(f"AnalysisSoundFile_Frequency Err:{str(e)}",3)
            #sys.exit(1)

    #解析音频文件分析躁声
    def AnalysisSoundFile_Noise(self,fileName):
        try:
            #加载音频文件:使用librosa加载音频文件。
            audio_file = fileName
            y, sr = librosa.load(audio_file)
            #特征提取:从音频信号中提取特征,例如梅尔频率倒谱系数(MFCC)
            mfccs = librosa.feature.mfcc(y=y, sr=sr)
            print(mfccs)
        except Exception as e:
            self.ShowLog("AnalysisSoundFile_Frequency Err:" + str(e), False)
            sys.exit(1)

    #读取json信息
    def ReadJsonInfo(self,fileName):
        try:
            if os.path.exists(fileName):
                f=open(fileName,'r',encoding='utf-8')
            return json.loads(f.read())
        except Exception as e:
            self.ShowLog("Read "+fileName+" Err:" + str(e),False)
            sys.exit(1)

    def identify_microphone_position(self,name):
        # 这里使用假设的命名规则,你需要根据实际情况修改
        if "front" in name.lower():
            return "Front Microphone"
        elif "rear" in name.lower() or "back" in name.lower():
            return "Rear Microphone"
        else:
            return "Unknown Position"

    #获取音频装置
    '''def get_audio_devices(self):
        try:
            # 运行命令获取音频设备列表
            result = subprocess.run(['aplay', '-l'], capture_output=True, text=True, check=True)
            # 打印输出结果
            print(result.stdout)
        except subprocess.CalledProcessError as e:
            print(f"Error: {e}")'''

    #打印的信息
    def ShowLog(self,log,isPass):
        try:
            if isPass == True:
                self.lbl_Result_Log.setStyleSheet("color:green;")
                self.logger.info(str(log))
            else:
                self.lbl_Result_Log.setStyleSheet("color:red;")
                self.logger.error(str(log))
            self.lbl_Result_Log.setText(str(log))
        except Exception as e:
            print("\033[1;31m" + str(e) + " \033[0m")
            self.logger.error(str(log))
            sys.exit(1)

if __name__=='__main__':
    app=QApplication(sys.argv)
    win=Ui_Form()
    win.Center()  # 居中
    win.show()
    sys.exit(app.exec_())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/313232.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3d云渲染用什么显卡比较好?3d云渲染显卡推荐

3D云渲染能加快渲染速度&#xff0c;是众多公司的首选方案&#xff0c;作为公司负责人&#xff0c;选择哪个平台值得思考&#xff0c;今天我就说下我的选择吧。 首先我们要了解云渲染的渲染方式&#xff0c;云渲染的渲染方式分两种&#xff0c;一种是CPU渲染&#xff0c;一种是…

C++程序员必备的面试技巧

“程序员必备的面试技巧&#xff0c;就像是编写一段完美的代码一样重要。在面试战场上&#xff0c;我们需要像忍者一样灵活&#xff0c;像侦探一样聪明&#xff0c;还要像无敌铁金刚一样坚定。只有掌握了这些技巧&#xff0c;我们才能在面试的舞台上闪耀光芒&#xff0c;成为那…

Windows 远程控制之 PsExec

1、介绍&#xff1a; PsExec 是一种轻量级 telnet 替代品&#xff0c;可让你在其他系统上执行进程&#xff0c;并为控制台应用程序提供完整交互性&#xff0c;而无需手动安装客户端软件。 PsExec 最强大的用途包括在远程系统上启动交互式命令提示符&#xff0c;以及 IpConfig …

【LeetCode】2619. 数组原型对象的最后一个元素

数组原型对象的最后一个元素 题目题解 题目 请你编写一段代码实现一个数组方法&#xff0c;使任何数组都可以调用 array.last() 方法&#xff0c;这个方法将返回数组最后一个元素。如果数组中没有元素&#xff0c;则返回 -1。 你可以假设数组是 JSON.parse 的输出结果。 示例 …

Postgres 中文周报:Postgres Weekly 537 期

本周报由 Cloudberry Database 社区编译自英文版《Postgres Weekly》&#xff0c;译文较原文有所调整。 推荐博文 &#x1f3c6; PostgreSQL: The DBMS of the Year 2023 PostgreSQL 荣获 DB-Engines 网站 2023 年度 DBMS 冠军。DB-Engines 收集了 480 款数据库系统信息并跟踪…

JAVA循环结构

目录 if语句 1、if语句第一种格式 2、if的第二种格式 3、if的第三种格式 switch语句 1、switch格式 2、switch练习 3、switch规则 循环 1、格式 2、练习 if语句 1、if语句第一种格式 package 分支结构;import java.util.Scanner;public class ifjiegou {public sta…

C Primer Plus 第6版 编程练习 chapter 13

文章目录 1. 第1题1.1 题目描述1.2 编程源码1.3 结果显示 2. 第2题2.1 题目描述2.2 编程源码2.3 结果显示 3. 第3题3.1 题目描述3.2 编程源码3.3 结果显示 4. 第4题4.1 题目描述4.2 编程源码4.3 结果显示 5. 第5题5.1 题目描述5.2 编程源码5.3 结果显示 6. 第6题6.1 题目描述6.…

​水经微图Web1.5.0版即将上线

让每一个人都有自己的地图&#xff01; 最近我们上线了水经微图&#xff08;简称“微图”&#xff09;Web1.4.0版&#xff0c;现在1.5.0版也即将上线&#xff0c;接下来的1.6.0版研发计划也已经确定好。 这里就来分享一下已上线的版本&#xff0c;即将上线的版本&#xff0c;…

virtualbox Ubuntu 网络连接

一、网络连接需求1—— 上网&#xff1a; 虚拟机默认的NAT连接方式&#xff0c;几乎不需要怎么配置&#xff0c;即可实现上网。 enp0s17以太网必须要开启&#xff0c;才能上网&#xff1b; 但是主机ping不通虚拟机&#xff0c;貌似可以ping 127.0.0.1; 二、主机和虚拟机相互p…

8年经验之谈!一文看懂性能测试的流程!

每天做着点点点测试有没有危机感&#xff1f; 突然有一天&#xff0c;领导说&#xff1a;“小王&#xff0c;今天把996福报系统压一下&#xff0c;下班前把压测报告发我邮箱。” 啥&#xff1f;压测&#xff1f;今天&#xff1f;报告&#xff1f;怎么压&#xff1f;怎么写&am…

java多线程面试集合(1)

1.并行和并发的区别 操作系统角度&#xff0c;线程是最小的执行单位 并行同一时刻两个线程都在执行&#xff0c;这就要求要有两个cpu。并发就是 同一时刻&#xff0c;只有一个执行但是在一个时间段内&#xff0c;两个线程都执行了&#xff0c;并发依赖于CPU切换线程&#xff…

20240112-【UNITY 学习】实现第一人称移动教程

1、创建一个空物体&#xff0c;挂载Rigidbody组件&#xff0c;并设置相应参数 2、在上述空物体下创建一个胶囊体&#xff0c;两个空物体&#xff0c;一个用来控制朝向&#xff0c;另一个用来控制摄像机 3、给摄像机创建一个父物体&#xff0c;并挂载脚本MoveCamera_01.cs using…

YOLOv8改进 更换层次化视觉变换器的网络结构

一、SwinTransformer论文 论文地址:arxiv.org/pdf/2103.14030.pdf 二、 SwinTransformer网络结构 SwinTransformer是一种基于transformer的图像分类网络结构。SwinTransformer是由微软亚洲研究院提出的,其特点是具有高效的计算和参数效率。 SwinTransformer的网络结构主要…

java每日一题——打印100以内个位和十位相同,尾数为1,3,5,7的数字

前言&#xff1a; 打好基础&#xff0c;daydayup! 题目&#xff1a;打印100以内个位和十位相同&#xff0c;尾数为1,3,5,7的数字 思路&#xff1a;1&#xff0c;个位通过对10求余数可求出1&#xff0c;3&#xff0c;5&#xff0c;7&#xff1b; 2&#xff0c;十位可通过先除10…

主流浏览器设置代理IP之Firefox浏览器

给浏览器设置代理IP是目前代理IP的主流使用场景之一&#xff0c;接下来小编就手把手教你如何对Firefox浏览器进行代理IP设置 注&#xff1a;本次使用IP来源于携趣代理平台https://www.xiequ.cn/index.html?4c51b56bhttps://www.xiequ.cn/index.html?4c51b56bFirefox浏览器内…

Java多线程并发篇----第九篇

系列文章目录 文章目录 系列文章目录前言一、阻塞状态(BLOCKED)二、线程死亡(DEAD)三、终止线程 4 种方式前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、…

ERROR in Plugin “react“ was conflicted .... 天坑留念-turborepo、eslint plugin

前两天项目代码拉下来&#xff0c;装完依赖启动的时候直接报错&#xff1a; [eslint] Plugin "react" was conflicted between ".eslintrc.js eslint-config-custom eslint-config-alloy/react" and "BaseConfig D:\pan\erp\test\business-servic…

矿泉水除硝酸盐的关键技术

在全球工业化和城市化的加速推进下&#xff0c;饮用水安全问题已经成为公众关注的焦点。在众多的水质污染物中&#xff0c;硝酸盐因其对健康的潜在危害而备受关注。为了确保饮用水的安全&#xff0c;去除水中的硝酸盐至关重要。本文将重点介绍离子交换树脂工艺在饮用水硝酸盐去…

学习C指针

指针基本介绍 计算机中的每个内存都有地址 整型分配4字节&#xff0c;字符分配1字节 &#xff0c;浮点数分配4字节 指针是一个变量&#xff0c;它存放着另外一个变量的地址 int a; int *p; p &a;// a 5; printf(p) //get a address print &a //get a address …

黑马苍穹外卖学习Day5

文章目录 Redis学习Redis简介准备工作Redis常用数据类型介绍各数据类型的特点Redis常用命令字符串操作命令哈希操作命令列表操作命令集合操作命令有序集合操作命令通用操作命令 在Java中操作Redis导入Spring Data Redis坐标配置Redis数据源编写配置类&#xff0c;创建RedisTemp…
最新文章