我正在尝试用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进行了修改。我的问题是,当我复制代码并尝试在我自己的项目中使用它时,它会编译但按下按钮时不会发出声音。有人能指出我正确的方向吗?
答案 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()并且它有效!
感谢所有阅读和/或回复的人。