首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用unicode版本Windows : mciSendString()

如何使用unicode版本Windows : mciSendString()
EN

Stack Overflow用户
提问于 2019-11-01 12:36:59
回答 3查看 862关注 0票数 1

我正在Windows 10上测试Python包:播放声音

它似乎有一些字符的路径名,如"c:\sauté“和宽字符的问题。所以它找不到文件。

命令错误275 :打开"C:\sauté.wav“别名playsound_0.4091468603477375找不到指定的文件。确保路径和文件名是正确的。

我尝试使用unicode版本的mciSendStringW()。原来,mciSendStringW根本不识别编码的命令。我不知道我现在还能做什么。

代码语言:javascript
复制
def winCommand(*command):
    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

prj站点:https://pypi.org/project/playsound/ (包括安装和快速启动指南)

src代码:https://raw.githubusercontent.com/TaylorSMarks/playsound/master/playsound.py

微软mciSendString函数:https://learn.microsoft.com/en-us/previous-versions/dd757161(v=vs.85)

EN

回答 3

Stack Overflow用户

发布于 2019-11-02 23:46:06

当使用wide函数mciSendStringW时,不应该对字符串进行编码。因此,您的行应该简单地读command = ' '.join(command)。至少在Python3.6的Windows10机器上是这样的。

要进行双重检查,您可以运行下面的代码。第二个错误代码将是296,这只是抱怨它是错误的文件类型,因为我们创建一个空文件进行测试。

代码语言:javascript
复制
from ctypes import c_buffer, windll
from sys import getfilesystemencoding

if __name__ == '__main__':
    buf = c_buffer(255)
    filesystemencoding = getfilesystemencoding()
    filename = r'.\sauté.wav'
    # create the file if it doesn't exist
    file = open(filename, 'w+')
    file.close()

    # ASCII
    command = 'open ' + filename
    byte_string_command = command.encode(filesystemencoding)

    errorCode = int(windll.winmm.mciSendStringA(byte_string_command, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

    # Unicode
    errorCode = int(windll.winmm.mciSendStringW(command, buf, 254, 0))
    # errorCode should be 296: The specified file cannot be played
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))
票数 0
EN

Stack Overflow用户

发布于 2019-11-05 02:27:23

没有声音,尽管它返回"0“(成功)。我的是Python3.7和Win10。我也试过utf-8,utf-16-le,没什么效果。

您需要添加wait标志。有了这个标志,您确实可以等待被调用的函数完成。你能真正播放你的文件的原因。在你移除它的情况下,它将启动游戏,并在关闭它之后立即开始。

整个守则(ASCII):

代码语言:javascript
复制
from ctypes import c_buffer, windll
from sys import getfilesystemencoding

if __name__ == '__main__':
    buf = c_buffer(255)
    filesystemencoding = getfilesystemencoding()
    filename = r'.\file_example.mp3'


    # ASCII
    command = 'open ' + filename + ' alias test2'
    waitcommand = 'play test2 wait'
    byte_string_command = command.encode(filesystemencoding)
    waiting = waitcommand.encode(filesystemencoding)
    errorCode = int(windll.winmm.mciSendStringA(byte_string_command, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

    errorCode = int(windll.winmm.mciSendStringA(waiting, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

UNICODE:

代码语言:javascript
复制
from ctypes import c_buffer, windll
from sys import getfilesystemencoding

if __name__ == '__main__':
    buf = c_buffer(255)
    filesystemencoding = getfilesystemencoding()
    filename = r'.\file_example.mp3'


    # ASCII
    command = r'open ' + filename + r' alias test2'
    waitcommand = r'play test2 wait'
    byte_string_command = command.encode(filesystemencoding)
    waiting = waitcommand.encode(filesystemencoding)

    # Unicode
    errorCode = int(windll.winmm.mciSendStringW(command, buf, 254, 0))
    # errorCode should be 296: The specified file cannot be played
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

    errorCode = int(windll.winmm.mciSendStringW(waitcommand, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

如果代码有效,它将返回0: The specified command was carried out

注:

  1. sys.getfilesystemencoding()

返回用于在Unicode文件名和字节文件名之间转换的编码名称。为了实现最好的兼容性,在所有情况下都应该使用str作为文件名,尽管也支持将文件名表示为字节。接受或返回文件名的函数应该支持str或字节,并在内部转换为系统的首选表示形式。 这种编码总是与ASCII兼容的.应该使用os.fsencode()和os.fsdecode()来确保使用正确的编码和错误模式。在UTF-8模式下,任何平台上的编码都是utf-8 .在macOS上,编码是'utf-8‘。在Unix上,编码是区域编码。在Windows上,编码可能是'utf-8‘或'mbcs',这取决于用户配置。在版本3.6中更改: Windows不再保证返回'mbcs‘。有关更多信息,请参见PEP 529和_enablelegacywindowsfsencoding()。在版本3.7中更改:在UTF-8模式下返回‘UTF-8’。

  1. 使用别名

打开设备时,可以使用“别名”标志为设备指定设备标识符。此标志允许为具有冗长文件名的复合设备分配一个简短的设备标识符,并允许您打开同一文件或设备的多个实例。

  1. 避免使用等待

如果要播放“不等待”,则需要处理MCI_NOTIFY,设置回调窗口句柄,并在播放完成后处理MM_MCINOTIFYhwndCallback:如果在命令字符串中指定了“通知”标志,则为回调窗口的句柄。

票数 0
EN

Stack Overflow用户

发布于 2020-04-17 11:14:21

我也在测试播放声音(Python3.8,Windows 10),并且遇到了同样的问题,这个问题可以通过这个线程中的答案来解决。非常感谢所有的贡献者!

诀窍在于使用mciSendStringW而不是mciSendStringA,并在“play”命令中使用“等待”标志。

以下是修改后的代码:

代码语言:javascript
复制
def _playsoundWin(sound, block = True):

from ctypes import c_buffer, windll
from random import random
from time   import sleep

def winCommand(*command):
    buf = c_buffer(255)
    command = ' '.join(command)
    # errorCode = int(windll.winmm.mciSendStringA(command, buf, 254, 0)) # original line
    errorCode = int(windll.winmm.mciSendStringW(command, buf, 254, 0))
    if errorCode:
        errorBuffer = c_buffer(255)
        # windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254) # original line
        windll.winmm.mciGetErrorStringW(errorCode, errorBuffer, 254)
        exceptionMessage = ('\n    Error ' + str(errorCode) + ' for command:'
                            '\n        ' + command +
                            '\n    ' + errorBuffer.value)
        raise PlaysoundException(exceptionMessage)
    return buf.value

alias = 'playsound_' + str(random())
winCommand('open "' + sound + '" alias', alias)
# winCommand('set', alias, 'time format milliseconds') # is not needed
# durationInMS = winCommand('status', alias, 'length') # returns bytes!
# durationInMS = durationInMS.decode() # needed for the original command
# winCommand('play', alias, 'from 0 to', durationInMS)
winCommand('play', alias, 'wait') # 'wait' does the trick

if block:
    pass
    # sleep(float(durationInMS) / 1000.0) # don't know it's purpose 
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58659364

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档