LECKÉK:              

Saját ablak
Directdraw1
Directdraw2
Directdraw_3
Sprite_1

Sprite 2
Billentyű_1
Billentyű_2
Egér
Joystick
Midi
Mp3_Ogg
Directsound
Időzítők
Fájlkezelés

 

Üdvözöllek!

Legelőször rem-eld ki a midi és mp3 sorokat a projectből! Vagy ha jó a füled hagyd benn!
Ezek után rátérhetünk a wav formátum használatára!
Ehhez kell egy Directsound felület, ennek létrehozásakor keletkezik egy fő hangpuffer,és amennyi hangot szeretnénk,annyi másodlagos hanfpuffert kell készíteni.Szépen sorban be kell tölteni a hangokat....
Tehát hozzad létre a hang osztályt, egy új hpp fájlban a neve: wav.hpp!
//
// Hanghullámok
//
#ifndef _HANGOK_
#define _HANGOK_
//
#include <dsound.h>
extern HWND hwnd;

class WAV
{
public:
WAV();
~WAV();
bool initwave();
DWORD loadwave(LPCTSTR nev); //visszatér a wave hosszával
DWORD readwave(LPVOID buff); // a wave hosszával lefoglalt puffermutatóra másol
void playsound(int a=0,int a1=0,int b=0); // a és a1 lejátsza az a-val mutatott hangot,
int get_darab(){return ds_darab;}; //ha épp lejátszott akkor választ az a1 ig másikat ha b=0

//b <> 0 akkor folyamatos lejátszás
void stopsound (int);
void setvolume (int,int);
void restore (int);
protected:
LPDIRECTSOUND dsound; //dsound obj mutató
LPDIRECTSOUNDBUFFER dsbuff[32]; //dsoundbuffer
WAVEFORMATEX w_format; //hullámformátum információ
HMMIO hmmio; //handle a wave fájl-ra
DWORD w_hossz; //betöltött wave adat hossza
PBYTE w_data; //ideiglenesen betöltött Wave adatok mutatója
int ds_darab; //létrehozott hangpufferek száma;
void torol_buff();

};

Kommentezve van magyarázat később!
Megvalósításoknál először konstruktor és destruktor:
//
//MEGVALÓSÍTÁSOK
//
WAV::WAV()
{
dsound=NULL; ds_darab=0; hmmio=NULL; w_data=NULL;
for(int i=0;i<32;i++){dsbuff[i]=NULL;}

}
WAV::~WAV()
{
torol_buff();
}
//

A konstruktor kinulláz minden fontos mutatót, a destruktor meghívja a töröl függvényt.
Megvalósítása:
void WAV::torol_buff()
{
for( int i=0;i<32;i++) //32 puffer felszabadítása
{if(dsbuff[i])
{
dsbuff[i]->Release();dsbuff[i]=NULL;
}
}
if(dsound)
{
dsound->Release(),dsound=NULL;//Hang objektum megszüntetése
}
ds_darab=0;
}
//

Ha volt betöltve hang, azaz létrejött a másodlagos hangpuffer, akkor letörüljük. A legvégén magát a Directsound objektumot törüljük le.
Következik a  load függvény. Bemenő paraméternek kell adni a fájl nevét,és megnyitja olvasásra, azonosítja a wav formátumot, lefoglal egy ideiglenes tárterületet,és oda be is másolja az adatokat.
Amikor lefutott,visszaadja a fájl hosszát, de a memória cím és a belovasott adatmennyiség ott marad a w_data és a w_hossz változóban. A megvalósítása:
DWORD WAV::loadwave(LPCTSTR nev)
{
w_hossz=0;
MMCKINFO mmWave;
MMCKINFO mmFmt;
MMCKINFO mmData;
MMRESULT mResult;
ZeroMemory(&w_format,sizeof(WAVEFORMATEX));
ZeroMemory(&mmWave, sizeof(mmWave));
ZeroMemory(&mmFmt, sizeof(mmFmt));
hmmio=mmioOpen((char*)(nev),NULL,MMIO_READ);
if(!hmmio)
{
;goto hiba;//nincs ilyen fájl
}
//megszerezzük a formátum struktúráját
mResult=mmioSeek(hmmio,0,SEEK_SET);
mmWave.fccType=mmioStringToFOURCC("WAVE",0);
mmFmt.ckid=mmioDescend(hmmio,&mmWave,NULL,MMIO_FINDRIFF);
if(mResult != MMSYSERR_NOERROR)
{
;goto hiba;
}
mResult=mmioDescend(hmmio,&mmFmt,&mmWave,MMIO_FINDCHUNK);
if(mResult != MMSYSERR_NOERROR)
{
goto hiba;//rossz wave formátum
}
mResult=mmioRead(hmmio,(HPSTR)&w_format,sizeof(WAVEFORMATEX));
if(mResult==-1)
{
;goto hiba;//nem olvasható forma
}
//Megszerezzük a wave adatok hosszát
mResult=mmioSeek(hmmio,0,SEEK_SET);
mmData.ckid=mmioStringToFOURCC("data",0);
mResult=mmioDescend(hmmio,&mmWave,NULL,MMIO_FINDRIFF);
if(mResult !=MMSYSERR_NOERROR)
{
goto hiba;
}
mResult=mmioDescend(hmmio,&mmData,&mmWave,MMIO_FINDCHUNK);
if(mResult !=MMSYSERR_NOERROR)
{
goto hiba;//nem lehet megtalálni a wave hosszát
}
w_hossz=mmData.cksize;
//Beolvassuk a wave adatot memóriába
if(w_data)
{
delete w_data;w_data=NULL;
}
w_data=new BYTE [w_hossz];
if(!w_data)
{
goto hiba;//memóriahiba
}
ZeroMemory(w_data,w_hossz);
mResult=mmioRead(hmmio,(HPSTR)w_data,w_hossz);
if(mResult==-1)
{
goto hiba;//olvasáshiba
}
mmioClose(hmmio,0);hmmio=NULL;
return w_hossz;//megvan a hossz és beolvastuk a memóriába
hiba:
if(hmmio)
{
mmioClose(hmmio,0);hmmio=NULL;//lezárjuk a fájlt.
}
return 0;
}
Azért van szükség két lépcsőre a hang betöltéséhez,mert ahhoz hogy egy másodlagos hangpuffert létrehozzunk, kellene a nagysága! ezt oldja meg a load függvény visszaadva az adatok méretét.A read() függvény pedig a létrehozott hangpufferbe másolja az adatokat.Megvalósítása:

DWORD WAV::readwave(LPVOID buff)
{
CopyMemory(buff,w_data,w_hossz);
return w_hossz;
}

//

Kell még két tömb, az egyik felsorolja, hogy a pufferekbe hányszor és milyen hangot kell tölteni,
a másik pedig a fájlok nevei. Azért lehet szükség többször betölteni ugyanazt a hangot,mert tegyük fel, van felállítva 4-5 db tank a pályán, és a hatósugarába ér egy ellenség,ekkor ezeknek le kellene játszani a robbanás hangot. Igen ám de egyszerre egyet lehet lejátszani, pedig kellene mind az öt.
A play függvény oldja meg a problémát.Ime a 2 tömb:

static char index[]={0,1,1,1,1,1,0,3,2,-1};
static LPCTSTR nevek[]={"snd\\w1.wav","snd\\w2.wav","snd\\w3.wav","snd\\w4.wav","snd\\w5.wav"};

Azért kell függvényeken kívül tenni,hogy láthassa a restore függvény is!Ha elveszett a hangpuffer (mert más alkalmazás került előtérbe)helyre kell állítani a puffer tartalmát,és megint kell a név.
Most már minden megvan a hangok betöltéséhez,és a pufferek létrehozásához.Az initwave() függvény:

bool WAV::initwave()
{
BYTE* flag1;//betöltött hang mutatója
static int db=0;int i=0;

if(dsound)
{
torol_buff(); //ha volt, töröl minden hang objektumot
}
HRESULT inf;
inf=DirectSoundCreate(NULL, &dsound, NULL);//hangobjektum létrehozása
if(inf !=S_OK)return false;//dsound nem oké
inf=dsound->SetCooperativeLevel(hwnd,DSSCL_PRIORITY );
if(inf !=DS_OK)return false;
while(index[db] !=-1)//megállapítjuk mennyi a betöltendő hangok száma
{db++;}
for(i=0;i<db;i++) //és annyi másodlagos hangpuffert hozunk létre
{
// loadwave(nevek[index[i]]);
DSBUFFERDESC ddesc;
ZeroMemory(&ddesc, sizeof(DSBUFFERDESC));
ddesc.dwSize= sizeof(DSBUFFERDESC);
ddesc.dwFlags= DSBCAPS_CTRLDEFAULT;   
//esetleg ki kell ezt a sort venni egyes fordítóknál
ddesc.dwBufferBytes=loadwave(nevek[index[i]]);
ddesc.lpwfxFormat= &w_format;
inf=dsound->CreateSoundBuffer(&ddesc,&dsbuff[i],NULL);
if(inf != DS_OK)return false;//hangpuffer nem oké
if(dsbuff[i]->Lock(0,ddesc.dwBufferBytes,(LPVOID*)&flag1,&w_hossz,NULL,0,0)!=DS_OK)
return false; //nem lehet zárolni a h puffert
readwave(flag1); //másolunk
if(dsbuff[i]->Unlock(flag1,w_hossz,NULL,0) !=DS_OK)
{
return false;//nem lehet felszabadítani a hangpuffert
}
ds_darab++;// az eddig betöltött hangok száma
}
return true;
}

Kommentezve van.Lássuk a playsound(...) függvényt:
void WAV::playsound(int a,int a1,int b)
{
int sv=a;
pl1: if(!dsbuff[sv])return;
if(sv>ds_darab)return;
DWORD status=0;
dsbuff[sv]->GetStatus(&status);
if(status & DSBSTATUS_BUFFERLOST) restore(sv);
status=0;
dsbuff[sv]->GetStatus(&status);
if((status & DSBSTATUS_PLAYING) ==DSBSTATUS_PLAYING) //ha épp játszott
{ //akkor veszi a következőt
if(!a1)return; //ha mind épp lejátszott akkor
sv++; //az eredetit elölről kezdi
if(sv<=(a+a1))goto pl1; //ha a1 nem NULLA !!
sv=a;
dsbuff[sv]->SetCurrentPosition(0);
return;
}
dsbuff[sv]->Play(0,0,b);
}

Úgy működik,hogy első paraméter a lejátszandó puffer száma, második pedig az hogy ha éppen ez lejátszás alatt van,akkor még hány közül választhat. Tehát alapból nulla az értéke,de ha 5  akkor még ennyit néz meg,hogy lejátszott-e. Ha mind lejátszott,akkor az eredetinek a pointerét visszaállítja nullára.Tehát azt játssza le elölről. A 3. pedig,hogy ismétli.e önmagát,vagy nem.

A restore() függvény:
void WAV::restore(int a)
{

HRESULT inf;
BYTE* flag1;
inf=dsbuff[a]->Restore();
if(inf !=DS_OK)return;//Ha nem sikerülne visszaállítani a hangpuffert akkor nincs mit tenni
if(dsbuff[a]->Lock(0,loadwave(nevek[index[a]]),(LPVOID*)&flag1,&w_hossz,NULL,0,0)!=DS_OK)
{
MessageBox(hwnd,"soundbuffer lock hiba","",0);return ;
}
readwave(flag1);
if(dsbuff[a]->Unlock(flag1,w_hossz,NULL,0) !=DS_OK)return;
}

Végül is a helyreállított pufferbe visszatölti az adatokat.
Maradt még 2 függvény:
void WAV::setvolume(int a,int b) //a= melyik puffer b= hangerő (0 - -10000)
{
if(a>ds_darab)return;
dsbuff[a]->SetVolume(b);
}

void WAV::stopsound(int a)
{
if(a>ds_darab)return;
dsbuff[a]->Stop();
dsbuff[a]->SetCurrentPosition(0); // ez visszaállítja az elejére ha kell és következőnél
} //előröl kezdi

Akkor már csak használni kell! Ne felejtsél el egy mappát a wav hangoknak snd néven és tegyél bele egy pár wav formátumú hangot!
Ne felejtsd el a projecthez csatolni a dsound.lib   vagy a libdsound.a fájlokat.

Használata a Main.cpp-ben:

#include <Sprite.hpp>
#include <wav.hpp>

//
//
//dekralációk
HINSTANCE hinstance;
RAJZ rajz;
INPUT input;
WAV wav;
SPRITE sprite;

Az init függvényt az ablakunk létrehozása után lehet meghívni,mert a hwnd csak azután kap értéket! tehát:
ShowCursor(false);
wav.initwave();
if(!rajz.init())MessageBox(NULL,"directdraw nem oké","",0);
input.init_key();
input.init_mouse();
input.init_joy ();

Lejátszás és hangerő állítása:

while (fut)
{
static int hangero=0;
if(input.get_key(DIK_A,true))wav.playsound(7,0,1);
if(input.get_key(DIK_ADD)){if(hangero<0)hangero+=10;wav.setvolume(7,hangero);};
if(input.get_key(DIK_SUBTRACT )){if(hangero>-10000)hangero-=10;wav.setvolume(7,hangero);};



uzenetkezelo();
sprite.frissit();
input.get_key(0,true);//csak azért hívjuk meg,hogy az esc-re kilépjen
rajz.kiirbetu(" A betű folyamatos lejátszás",500,10);
rajz.kiirbetu(" NUM + hangerő növelése" ,500,30);
rajz.kiirbetu(" NUM - hangerő csökkentése" ,500,50);
rajz.flip();

}
return 0;
A sprite osztályban a frissít() függvényben ki kell REM elni a rajz.flip(); sort:
babu_mozgat_m();
babu_mozgat_joy();
// rajz.flip();

fordít futtat !
Ha jól csináltál mindent, akkor az A betűre elindul a hang lejátszása ismételve,és a hangerőt tudod növelni,csökkenteni!

Még egy sor utasítás van a sorozat lejátszásához!A Frissít függvényben(sprite osztály)az ütközésvizsgálatnál módosítunk:
void SPRITE::frissit()
{
static bool flag=false;static int szamlalo=10;
rajz.rajzol(0,0,0,800,600,-1,0,0);//háttér
sp_rajz();
szamlalo--;
if(!szamlalo){szamlalo=10;if(sp_utk(0))wav.playsound(1,4,0);};

anim();
sp_mozgat();

Ha a golyónk nekiütközik a csillagnak,akkor lejátssza többször a hangot.

fordít- futtat.

Jönnek az időzítők.

Addig is itt a kód:

vissza