使用C ++ / CLI时,不会产生声音

时间:2014-10-06 18:25:57

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

我正在尝试用Visual C ++编写一个程序,该程序将根据从黑白视频的像素获得的音量和频率输入播放声音。首先,我首先尝试播放sans参数的声音(稍后我将添加)。我已经将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进行了修改。我的问题是,当我复制代码并尝试在我自己的项目中使用它时,它会编译但按下按钮时不会发出声音。有人能指出我正确的方向吗?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

我补充说:

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

到Sound :: init()并且它有效!

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