所以我有一个非常奇怪的问题,确实很难复制。根据文件类型,我正在使用几个不同的库播放声音。我希望能够删除声音,因此在使用os.remove()删除文件之前,我先清除音频播放器(通过重新分配audio_player变量),那是当我收到权限错误时,但仅当我清除了音频播放器时使用pygame。我不知道为什么会发生这种情况,但是我已经能够始终如一地将其复制到一个测试文件中,这既是该文件又是原始文件。它与SoundPlayer.reload_sound_from_different_file()
原始aka AudioPlayer
import pygame
import MetaData
import os
import time
from random import random
from PyQt5.QtCore import pyqtSignal, QObject, QRunnable, pyqtSlot
class PlaysoundException(Exception):
pass
class SoundSigs(QObject):
time_changed = pyqtSignal()
set_current_time = pyqtSignal(float)
reset_cursor = pyqtSignal()
error = pyqtSignal(str)
class SoundPlayer(QRunnable):
def __init__(self):
super(SoundPlayer, self).__init__()
self.path = ''
self.signals = SoundSigs()
self.wav_list = ['.wav']
self.pygame_list = ['.flac', '.ogg', '.mp3']
self.current_result = ''
self.pixel_time_conversion_rate = 0
self.audio_player = AudioPlayer()
def reset(self):
self.audio_player.stop()
self.audio_player = AudioPlayerPlaceholder()
def space_bar(self):
if self.audio_player.ended:
self.audio_player.goto(0)
elif self.audio_player.playing:
self.audio_player.pause()
else:
self.audio_player.resume()
@pyqtSlot()
def run(self):
while True:
while self.audio_player.playing and not self.audio_player.ended and not \
self.audio_player.passed_download_head:
time.sleep(.003)
self.signals.time_changed.emit()
time.sleep(.01)
def load(self, path, pixel_time_conversion_rate):
self.pixel_time_conversion_rate = pixel_time_conversion_rate
self.audio_player = self.get_correct_audio_player(path)
self.audio_player.load(path)
def get_correct_audio_player(self, path):
file_type = os.path.splitext(path)[1].lower()
if file_type in self.wav_list:
return WavPlayer()
elif file_type in self.pygame_list:
return PygamePlayer()
def load_segment(self, path, true_duration, pixel_time_conversion_rate):
current_time = self.audio_player.current_time
playing = self.audio_player.playing
self.audio_player.stop()
self.audio_player = self.get_correct_audio_player(path)
self.pixel_time_conversion_rate = pixel_time_conversion_rate
self.audio_player.load_segment(path, true_duration)
self.audio_player.goto(current_time)
if playing:
self.audio_player.play()
def preload(self, true_duration, pixel_time_conversion_rate):
self.audio_player.stop()
self.signals.time_changed.emit()
self.audio_player = AudioPlayerPlaceholder()
self.pixel_time_conversion_rate = pixel_time_conversion_rate
self.audio_player.preload(true_duration)
self.audio_player.play()
def reload_sound_from_different_file(self, path):
current_time = self.audio_player.current_time
playing = self.audio_player.playing
self.audio_player.stop()
self.audio_player = self.get_correct_audio_player(path)
self.audio_player.load(path)
self.audio_player.goto(current_time)
if playing:
self.audio_player.play()
@staticmethod
def calculate_px_time_conversion_rate(waveform_width, sound_duration):
return waveform_width/sound_duration
def goto(self, position):
self.audio_player.goto(position/self.pixel_time_conversion_rate)
self.signals.time_changed.emit()
class AudioPlayerSigs(QObject):
error = pyqtSignal(str)
class AudioPlayer:
def __init__(self):
self.signals = AudioPlayerSigs()
self.loaded = False
self._playing = False
self.loop = False
self.segment = False
self._path = ''
self.path = ''
self._original_path = ''
self._meta_data = None
self._duration = 0
self.attempted_current_time = 0
self.passed_download_head = False
self._current_time_start = 0
self.current_time_stop = 0
self._current_time_stop = 0
self._current_time = 0
self.current_time = 0
def __del__(self):
self._meta_data = None
@property
def current_time_stop(self):
if not self.playing:
return self._current_time_stop
return time.time()
@current_time_stop.setter
def current_time_stop(self, value):
self._current_time_stop = value
@property
def playing(self):
return self._playing
@playing.setter
def playing(self, value):
if value:
self._current_time_start = time.time()
else:
self._current_time = self.current_time
self.current_time_stop = time.time()
self._current_time_start = time.time()
self._playing = value
@property
def path(self):
return self._path
@path.setter
def path(self, value):
self._original_path = value
self._path = get_short_path_name(value)
@property
def current_time(self) -> int:
if self.playing:
return int((self.current_time_stop - self._current_time_start)*1000) + self._current_time
return self._current_time
@current_time.setter
def current_time(self, value):
self._current_time_start = time.time()
self._current_time = value
@property
def meta_data(self):
if self.loaded:
return self._meta_data
self._meta_data = self.get_meta_file()
return self._meta_data
@property
def true_duration(self):
return self.meta_data['duration']
@property
def duration(self):
if self.segment:
return self._duration
return self.true_duration
@property
def ended(self):
return self.duration <= self.current_time
def get_meta_file(self):
return MetaData.get_meta_file(self._original_path)
def load(self, path):
self.path = path
self._meta_data = self.get_meta_file()
self.loaded = True
self._load(self.path)
def _load(self, path):
pass
def reload(self, path, playing):
self.path = path
self._meta_data = self.get_meta_file()
self.stop()
self._reload(path)
self.loaded = True
if playing:
self.play()
def _reload(self, path):
pass
def play(self):
if not self.playing:
self.playing = True
self._play()
def _play(self):
pass
def pause(self):
if self.playing:
self.playing = False
self._pause()
def _pause(self):
pass
def resume(self):
if not self.playing:
self.playing = True
self._resume()
def _resume(self):
pass
def stop(self):
if self.loaded:
self._reset()
self._stop()
def _stop(self):
pass
def goto(self, position):
self.current_time = position
if self.segment and position >= self.true_duration:
self.pause()
self.attempted_current_time = position
self.passed_download_head = True
else:
self._goto(position)
if not self.playing:
self._pause()
def _goto(self, position):
pass
def _reset(self):
self.loaded = False
self.playing = False
self.loop = False
self.segment = False
self.passed_download_head = False
self.current_time = 0
def end(self):
if self.loop:
self.goto(0)
self.play()
def swap_file_with_complete_file(self, path):
if self.passed_download_head:
current_time = self.attempted_current_time
else:
current_time = self.current_time
playing = self.playing
self.stop()
self.reload(path, playing)
self.goto(current_time)
load_rest_of_segment = swap_file_with_complete_file
def swap_file_with_incomplete_file(self, path, duration):
current_time = self.current_time
self.stop()
self.load_segment(path, duration)
self.goto(current_time)
self.play()
def load_segment(self, path, duration):
self.segment = True
self._duration = duration
self.load(path)
class WavPlayer(AudioPlayer):
def __init__(self):
super(WavPlayer, self).__init__()
self.alias = ''
def __del__(self):
self.win_command('close', self.alias)
def _load(self, path):
self.alias = 'playsound_' + str(random())
self.win_command('open "' + self.path + '" alias', self.alias)
self.win_command('set', self.alias, 'time format milliseconds')
def _reload(self, path):
self._load(path)
def _play(self):
self.win_command('play', self.alias, 'from', str(round(self.current_time)), 'to', str(self.duration))
def _pause(self):
self.win_command('pause', self.alias)
def _resume(self):
self.win_command('play', self.alias)
def _stop(self):
self.win_command('stop', self.alias)
def _goto(self, position):
self.win_command('play', self.alias, 'from', str(round(position)), 'to', str(self.duration))
@staticmethod
def win_command(*command):
from ctypes import c_buffer, windll
from sys import getfilesystemencoding
buf = c_buffer(255)
command = ' '.join(command).encode(getfilesystemencoding())
errorCode = int(windll.winmm.mciSendStringA(command, buf, 254, 0))
if errorCode:
errorBuffer = c_buffer(255)
windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
exceptionMessage = ('\n Error ' + str(errorCode) + ' for command:'
'\n ' + command.decode() +
'\n ' + errorBuffer.value.decode())
raise PlaysoundException(exceptionMessage)
return buf.value
class PygamePlayer(AudioPlayer):
def __init__(self):
super(PygamePlayer, self).__init__()
pygame.mixer.pre_init(48000, -16, 2, 1024)
def __del__(self):
pygame.mixer.quit()
self.path = None
print('deleted')
def _load(self, path):
frequency = int(self.meta_data['sample rate'])
channels = int(self.meta_data['channels'])
pygame.mixer.quit()
pygame.mixer.init(frequency=frequency, channels=channels)
try:
pygame.mixer.music.load(path)
except pygame.error:
self.signals.error.emit("Couldn't play this file! It may be that it's corrupted. "
"Try downloading it again.")
def _reload(self, path):
try:
pygame.mixer.music.load(self.path)
except pygame.error:
self.signals.error.emit("Couldn't play this file! It may be that it's corrupted. "
"Try downloading it again.")
def _play(self):
try:
pygame.mixer.music.play()
except Exception as e:
self.signals.error.emit(e)
def _pause(self):
pygame.mixer.music.pause()
def _resume(self):
pygame.mixer.music.unpause()
def _stop(self):
pygame.mixer.music.stop()
def _goto(self, position):
try:
self._reload(self.path)
pygame.mixer.music.play(start=round(position)/1000)
except pygame.error:
pygame.mixer.music.set_pos(position)
class AudioPlayerPlaceholder(AudioPlayer):
def __init__(self):
super(AudioPlayerPlaceholder, self).__init__()
self.passed_download_head = True
@property
def current_time(self):
return self._current_time
@current_time.setter
def current_time(self, value):
self._current_time = value
@property
def ended(self):
return False
def goto(self, position):
self.current_time = position
def preload(self, duration):
self._duration = duration
self.current_time = 0
def get_short_path_name(long_name):
from ctypes import wintypes
import ctypes
_GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
_GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD]
_GetShortPathNameW.restype = wintypes.DWORD
"""
Gets the short path name of a given long path.
http://stackoverflow.com/a/23598461/200291
"""
output_buf_size = 0
while True:
output_buf = ctypes.create_unicode_buffer(output_buf_size)
needed = _GetShortPathNameW(long_name, output_buf, output_buf_size)
if output_buf_size >= needed:
return output_buf.value
else:
output_buf_size = needed
测试文件
from AudioPlayer import SoundPlayer
import time
import os
file_name = "<file path>"
player = SoundPlayer()
player.load(file_name, 1)
player.audio_player.play()
time.sleep(5)
player.reload_sound_from_different_file(file_name)
time.sleep(2)
player.audio_player.stop()
player.reset()
time.sleep(1)
os.remove(file_name)
我知道这个问题要问很多,但是我已经坚持了3天,哈哈。任何帮助将不胜感激!
答案 0 :(得分:0)
几周前,我在工作中的应用程序上遇到Windows安全性类似的问题。最终为我解决的是从命令提示符设置为管理员的批处理文件中调用脚本。如果要尝试,请使用以下命令创建一个.bat
文件:
cd path/to/your/script
python myscript.py
然后创建一个批处理文件的快捷方式,并在properties
标签中,依次选择advanced
和run as administrator
。每当双击文件并以我自己的方式克服这些权限错误时,它将以管理员身份运行所有脚本。它也可能对您有用。
答案 1 :(得分:0)
以某种方式,您安装的软件包可能不会被标记为受信任的应用程序,这是除尝试通过右键单击应用程序管理员并单击以管理员身份运行来临时授予应用程序管理员访问权限之外,尝试做的其他事情。
要取消阻止程序包,请导航至/python/lib/
,然后查找您已安装的程序包(如果有)或程序中所述的程序包。右键单击所有python文件,根据情况,它可能会显示一个框,显示“取消阻止该程序”。如果是,请选中该框并单击“应用”,然后单击“确定”。我建议对您正在使用的软件包中的每个文件执行此操作。
如果这行不通(这很有可能不行,因为这是一个不寻常的错误),请告诉我。
答案 2 :(得分:0)
好的,我知道了!问题是,当您多次退出混音器时,pygame确实不喜欢它。每次初始化新播放器时,我都会退出,由于某种原因,第二次播放器无法完全释放文件。我最终要做的是先将文件加载到内存中,然后以这种方式将其提供给pygame,然后我可以在闲暇时删除它:)