【问题标题】:When using C++/CLI no sound is produced使用 C++/CLI 时不发出声音
【发布时间】:2014-12-01 01:54:12
【问题描述】:

我正在尝试用 Visual C++ 编写一个程序,该程序将根据从黑白视频像素获得的音量和频率输入来播放声音。首先,我首先尝试让声音播放无参数(稍后我将添加)。我已经在项目中包含了 winmm.lib。

我有可以编译但不播放声音的代码。我目前的代码如下:

sound.h(为我提供,用于另一个项目):

//file: soundthread.h
#include <Windows.h> //new
#include <mmsystem.h>

#ifndef SOUNDTHREAD_H
#define SOUNDTHREAD_H

class Sound {
    public:

        static void init();
        static void close(){waveOutReset(hWaveOut); waveOutClose(hWaveOut);};
        static void writeAudioBlock(LPSTR block);

    private:
        static HWAVEOUT hWaveOut;
};
#endif

sound.cpp(为我提供,用于另一个项目):

#include "stdafx.h"
#include "sound.h"
#include <mmsystem.h>
#include <mmreg.h>

HWAVEOUT Sound::hWaveOut;

void Sound::init(){
    WAVEFORMATEX wfx; 
    wfx.nSamplesPerSec = 8000; 
    wfx.wBitsPerSample = 8; 
    wfx.nChannels = 1; 
    wfx.cbSize = 0; 
    wfx.wFormatTag = WAVE_FORMAT_PCM;
   // wfx.nBlockAlign = (wfx.wBitsPerSample >> 2) * wfx.nChannels;
    wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
    wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
/*
    if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL)
    != MMSYSERR_NOERROR) 
    //  int tt;
    //  tt = waveOutOpen(&hWaveOut, ((UINT)1), &wfx, 0, 0, CALLBACK_NULL);
    //  if(tt != MMSYSERR_NOERROR) {
            fprintf(stderr, "unable to open WAVE_MAPPER device\n");
            int tt;
            tt = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
            MessageBox(0, "unable to open WAVE_MAPPER device\n", "Error", MB_ICONERROR|MB_OK);
    /* DBG:     tt=MMSYSERR_ALLOCATED;
        tt=MMSYSERR_BADDEVICEID;
        tt=MMSYSERR_NODRIVER;
        tt=MMSYSERR_NOMEM;
        tt=WAVERR_BADFORMAT; //** this is it //
        tt=WAVERR_SYNC;  // END DBG */

//         ExitProcess(1);
//    }

}

void Sound::writeAudioBlock(LPSTR block) {
    WAVEHDR header;
    ZeroMemory(&header, sizeof(WAVEHDR));
    header.dwBufferLength = 500;
    header.lpData = block;
    waveOutPrepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
    waveOutWrite(hWaveOut, &header, sizeof(WAVEHDR));
    do {
        Sleep(100);
    }while(waveOutUnprepareHeader(hWaveOut,&header,sizeof(WAVEHDR)) == WAVERR_STILLPLAYING);

}

soundplay.h(由我创建,用于保存提供的 OnSound() 函数):

#ifndef SOUNDPLAY_H //SOUNDPLAY_H_INCLUDED
#define SOUNDPLAY_H //SOUNDPLAY_H_INCLUDED

#include "sound.h"

void OnSound(); //update this w/ freq and intensity paramaters

#endif // SOUNDPLAY_H_INCLUDED

soundplay.cpp(由我创建,用于保存提供的 OnSound() 函数):

#include "stdafx.h"
#include <windows.h>
#pragma comment(lib, "winmm.lib")
#include <math.h> //used to be under sound.h
#include "sound.h"
#include <mmsystem.h>
#define PI 3.141592653f
#include "soundplay.h" //new

void OnSound() 
{
    // produce a sin wave sound.
    float freq = 440.f;
    DWORD Fs=8000;
    int N=500;
    float* tt=new float[N];

    for(int i=0;i<N;i++)
    {
        tt[i]=(float)i/(float)Fs;
    }

    float intensity = 0.5f; //volume
    float *signal=new float[N];

    for(int i=0;i<N;i++)
    {
        signal[i]=intensity*sin(2.f*PI*freq*tt[i]);
    }

    BYTE* data=new BYTE[N];
    for(int i=0;i<N;i++)
    {
        data[i]=(BYTE)(signal[i]+128.f);
    }

    delete []signal;
    Sound::writeAudioBlock((LPSTR)data);
    delete []data;
    delete []tt;
}

Form1.h(来自 GUI 设计器的代码,包含触发 OnSound 播放声音的按钮):

#include "sound.h" //new
#include "soundplay.h" //new

#pragma once

namespace a2c {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    /// <summary>
    /// Summary for Form1
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
        }

    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::Button^  button1;
    protected: 

    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->SuspendLayout();
            // 
            // button1
            // 
            this->button1->Location = System::Drawing::Point(13, 225);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(75, 23);
            this->button1->TabIndex = 0;
            this->button1->Text = L"Sound Test";
            this->button1->UseVisualStyleBackColor = true;
            this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
            // 
            // Form1
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(292, 273);
            this->Controls->Add(this->button1);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
            this->ResumeLayout(false);

        }
#pragma endregion
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
        //code for sound production
        OnSound();
    }
    //NEW STUFF
    private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
                 Sound::init();
             }
    };
}

OnSound 和 sound.h 和 sound.cpp 的内容来自一个声音示例项目,该项目在 Visual Studio 6.0 中创建并针对用于播放声音的 Visual Studio 2010 进行了修改。我的问题是,当我复制代码并尝试在自己的项目中使用它时,它会编译但在按下按钮时不会播放声音。谁能指出我正确的方向?

【问题讨论】:

  • C++11 标准不知道声音。您需要一个特定于操作系统的库(或其他一些抽象的库,可能是libsdl...)
  • 我猜你检查了all these
  • @BasileStarynkevitch:我不认为这是一个 C++11 问题。它绝对是 Windows(他们最新的 VC++ 2013 只是部分兼容 C++11)。 VC++ 2010 不支持 C++11 的大部分内容。 OPs 问题表明它可以编译并运行,但没有播放声音的预期行为。附带说明mmsystem.h 是 Windows 为 Win32 声音系统的基本功能定义原型的地方。
  • 为什么不直接使用 .net? How to play a sound in C#, .NET
  • @crashmstr : 不是每个人都使用托管语言。有时这是毫无意义和不必要的开销。

标签: visual-studio-2010 audio c++-cli


【解决方案1】:

您的问题是将浮点 samples 缩放为 8 位无符号 data。由于强度为 0.5,因此样本将介于 -0.5 和 0.5 之间。添加 128 并截断到一个字节将为您提供 data 值 128 或 127 - 实际上为零。要扩展到 BYTE 的全部范围,您需要乘以 127。

BYTE* data=new BYTE[N];
for(int i=0;i<N;i++)
{
    data[i]=(BYTE)(signal[i]*127.f+128.f);
}

另外,除非你对量化失真没问题,否则我建议添加一些dither

【讨论】:

  • 感谢您的回复。我试了一下,还是没有声音。我不知道下一步该尝试什么。有什么想法吗?
【解决方案2】:

Michael Petch 关于音响系统的不完整初始化是正确的。

我补充说:

int tt;
tt = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);

到 Sound::init() 并且它起作用了!

感谢所有阅读和/或回复的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多