C控制台应用程序中的PlaySound?

新手上路,请多包涵

编辑所以代码是正确的(感谢 ta.speot.is) - 底部的新问题

所以我一直在玩这个级别的控制台,我们被要求制作我们的第一个“项目”进行评估。我已经完成了基本的应用程序.. 但我想稍微提高一下并添加一些声音。将从控制台播放的声音。

这个测试有效(有点),因为它会播放一个声音文件,但有两个问题……

  1. 当声音开始播放时,应用程序会冻结,直到它完成播放。

  2. 当我尝试编译为“发布”时,它会出现“链接错误”错误 - 致命错误 LNK1120: 1 unresolved externals。

 #include <iostream>
#include <windows.h>
#include <mmsystem.h>
using namespace std;

int main(){
    //PlaySound(TEXT("mywavsound.wav"), NULL, SND_FILENAME); - My erroring code
    PlaySound(TEXT("mywavsound.wav"), NULL, SND_FILENAME | SND_ASYNC);// - the correct code

    int test = 0;
    cin>>test;
    return 0;
}

所以我的问题是…

  1. 如何在不冻结控制台的情况下播放声音,例如,我可以在项目运行时播放循环音乐文件?如果我可以在它上面播放其他声音,那就太好了,例如,当你按下回车键时,它会在不停止音乐的情况下播放声音。

  2. 如何添加 wav 文件以便将其编译为发行版?

编辑

我知道 SND_ASYNC 东西,但我不知道如何使用它,如果没有东西不编译,我似乎无法使用它.. 有没有人有使用 SND_ASYNC 的代码示例 --- ?

编辑 2

所以我现在有这个工作….使用

PlaySound(TEXT("mysound.wav"), NULL, SND_FILENAME | SND_ASYNC);

现在我想知道如何一次播放 1 个或多个声音,因为如果我用该标志调用 PlaySound() 两次,它将停止第一个并播放第二个.. 有没有办法播放同时发出2个声音?

原文由 aJynks 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

如何在不冻结控制台的情况下播放声音?

如果你用谷歌搜索 PlaySound 这是第一个结果

fdwSound

SND_ASYNC 声音异步播放, PlaySound 声音开始后立即返回。要终止异步播放的波形声音,请调用 PlaySound 并将 pszSound 设置为 NULL

您应该熟悉搜索引擎及其功能。

如何添加 wav 文件以便将其编译为发行版?

您需要在发布和调试配置中链接 winmm.lib 。或者,添加

#pragma comment(lib, "winmm.lib")

到源代码的顶部。

原文由 ta.speot.is 发布,翻译遵循 CC BY-SA 4.0 许可协议

以下解决方案仅适用于 wav 文件

在我大学的第二个学期,我用 C++ 制作了一个控制台(ASCII)游戏作为学期项目。在制作该游戏时,需要播放多个音频文件。谷歌搜索后,我编写了以下代码:

音频.h

 #pragma once
#include <xaudio2.h>
#include <iostream>
#include <string>
using namespace std;
#ifdef _XBOX
#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'
#endif

#ifndef _XBOX
#define fourccRIFF 'FFIR'
#define fourccDATA 'atad'
#define fourccFMT ' tmf'
#define fourccWAVE 'EVAW'
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'
#endif
class Audio
{
private:
    HRESULT hr;
    IXAudio2* pXAudio2;
    IXAudio2MasteringVoice* pMasterVoice;
    HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition);
    HRESULT ReadChunkData(HANDLE hFile, void* buffer, DWORD buffersize, DWORD bufferoffset);
public:
    Audio();
    int Play(string path, float volume = 1, bool ShouldLoop = false); // plays the audio file with specified volume and can be looped
    string BasePath; // Directory where all audio files (relevant to project) are stored i.e if all audio files are stored in "D:\game" than set BasePath to "D:\game", this will be automatically added in path of every audio file
};

音频.cpp

 #include "Audio.h"
Audio::Audio()
{
    BasePath = "";
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (FAILED(hr))
        cout << hr;
    pXAudio2 = nullptr;
    if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
        cout << hr;

    pMasterVoice = nullptr;
    if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice)))
        cout << hr;
}
int Audio::Play(string path, float volume, bool ShouldLoop) {
    path = BasePath + "\\" + path;
    WAVEFORMATEXTENSIBLE wfx = { 0 };
    XAUDIO2_BUFFER buffer = { 0 };
#ifdef _XBOX
    char* strFileName = path;
#else
    TCHAR* strFileName = new TCHAR[path.size() + 1];
    strFileName[path.size()] = 0;
    std::copy(path.begin(), path.end(), strFileName);
#endif
    // Open the file
    HANDLE hFile = CreateFile(
        strFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (INVALID_HANDLE_VALUE == hFile)
        return HRESULT_FROM_WIN32(GetLastError());

    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
        return HRESULT_FROM_WIN32(GetLastError());
    DWORD dwChunkSize;
    DWORD dwChunkPosition;
    //check the file type, should be fourccWAVE or 'XWMA'
    FindChunk(hFile, fourccRIFF, dwChunkSize, dwChunkPosition);
    DWORD filetype;
    ReadChunkData(hFile, &filetype, sizeof(DWORD), dwChunkPosition);
    if (filetype != fourccWAVE)
        return S_FALSE;

    FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition);
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition);
    FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition);
    BYTE* pDataBuffer = new BYTE[dwChunkSize];
    ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);

    buffer.AudioBytes = dwChunkSize;  // size of the audio buffer in bytes
    buffer.pAudioData = pDataBuffer;  // buffer containing audio data
    buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer
    if (ShouldLoop) buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
    IXAudio2SourceVoice* pSourceVoice;
    if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx))) cout << hr;
    //if (FAILED(hr = pSourceVoice->SetSourceSampleRate(20000))) cout << hr;
    if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&buffer))) cout << hr;
    //if (FAILED(hr = pSourceVoice->SetFrequencyRatio(1.2))) cout << hr;
    pSourceVoice->SetVolume(volume);
    if (FAILED(hr = pSourceVoice->Start(0)))
        cout << hr;

    return 0;
}

HRESULT Audio::FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition)
{
    HRESULT hr = S_OK;
    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
        return HRESULT_FROM_WIN32(GetLastError());

    DWORD dwChunkType;
    DWORD dwChunkDataSize;
    DWORD dwRIFFDataSize = 0;
    DWORD dwFileType;
    DWORD bytesRead = 0;
    DWORD dwOffset = 0;

    while (hr == S_OK)
    {
        DWORD dwRead;
        if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL))
            hr = HRESULT_FROM_WIN32(GetLastError());

        if (0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL))
            hr = HRESULT_FROM_WIN32(GetLastError());

        switch (dwChunkType)
        {
        case fourccRIFF:
            dwRIFFDataSize = dwChunkDataSize;
            dwChunkDataSize = 4;
            if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());
            break;

        default:
            if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT))
                return HRESULT_FROM_WIN32(GetLastError());
        }

        dwOffset += sizeof(DWORD) * 2;

        if (dwChunkType == fourcc)
        {
            dwChunkSize = dwChunkDataSize;
            dwChunkDataPosition = dwOffset;
            return S_OK;
        }

        dwOffset += dwChunkDataSize;

        if (bytesRead >= dwRIFFDataSize) return S_FALSE;

    }

    return S_OK;

}
HRESULT Audio::ReadChunkData(HANDLE hFile, void* buffer, DWORD buffersize, DWORD bufferoffset)
{
    HRESULT hr = S_OK;
    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN))
        return HRESULT_FROM_WIN32(GetLastError());
    DWORD dwRead;
    if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL))
        hr = HRESULT_FROM_WIN32(GetLastError());
    return hr;
}

在主文件中像这样使用它

#include "Audio.h"

string getExePath(string x) // removes fileName from path i.e "D:\path\to\exe\sample.exe" changes it into "D:\path\to\exe"
{
    std::string f = x;
    return f.substr(0, f.find_last_of("\\/"));
}

int main(int argc, char* argv[]) {
    string exeLocation = argv[0]; // returns path of currently running program i.e "D:\path\to\exe\sample.exe"
    Audio audioManager;
    audioManager.BasePath = getExePath(exeLocation);
    audioManager.Play("bg.wav");
    while(1){}
    return 0;
}

笔记

我不知道使用此代码的缺点,因为我是很久以前写的,并且大部分代码都取自 XAudio2 的文档或其他一些来源

原文由 bakar-bst 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏