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!

A midi osztályhoz kissé hasonló lesz az mp3 és ogg fájlok lejátszása.
Jobbnak láttam,ha létrehozok egy struktúrát, amiben el lehet tárolni a betöltött zene memóriacímét,és amikor lejátszásra kerül,akkor a dll fájl visszaad egy számot,mégpedig a megnyitott hangpuffer azonosítóját, tehát erre a számra lehet hivatkozni, amikor műveleteket végzünk az adott hangobjektumon, mint  lejátszás, hangerő, stop stb.
Hogy ne legyen a pause meghívásával gond, létrehoztam egy logikai változót is,hogy megállított, vagy nem a lejátszás.  Hozz Létre egy uj fájlt Mp3_ogg.hpp néven, és a megszokott módon építsed fel az osztályt:
//
// Ogg és mp3 lejátszása:
//
#ifndef _OGG_MP3_
#define _OGG_MP3_
//
#include <fmod.h>
#pragma comment(lib,"fmodvc.lib")

#define MAX_CSATORNA 8 //egyszerre több zenét nem akarunk,ez is sok
//
typedef struct
{
FSOUND_SAMPLE* szam; //létrehozott objektum címe
int csatorna; // a felhasznált hangcsatorna száma
bool pause;
} HOBJ, *LPHOBJ ; //Hangobjektum és mutatója

class ZENE
{
public:
ZENE();
~ZENE();
bool zene_init( int melyik,int hova=0,bool loop=false);//hova= hányadik tömbelembe
void zene_play( int melyik);
void zene_stop( int melyik);
void zene_hangero(int melyik,int volume);
void zene_torol( int melyik); //felszabadítja a csatornát következő zenének
void zene_pause(int melyik,bool paused=false);

protected:
LPHOBJ zenek[32]; //32db zeneszám mutatónak hely
bool fsound_init(); //dll betöltése és init
};

Nos látható, hogy a védett tagváltozók között szereplő LPHOBJ zenek[32]  csak egy 32 elemű
mutatótömb,tehát üres majd ha betöltjük a zeneszámot, akkor kap értéket.

Megvalósítások:

ZENE::ZENE()
{
for(int i=0;i<MAX_CSATORNA ;i++)
{
zenek[i]=NULL;
}
fsound_init();
}
ZENE::~ZENE()
{
for(int i=0;i<MAX_CSATORNA;i++)
{
if(!zenek[i]){delete zenek[i];zenek[i]=NULL;}
}
}

A konstruktor meghív egy inicializáló függvényt,ami betölti a dll.t. A destruktor pedig felszabadít minden létező zeneszám memóriát,és a dll-t is.
Az fsound_init() függvény:
bool ZENE::fsound_init()
{
if (FSOUND_GetVersion() < FMOD_VERSION)
{
// err("rossz dll");
return false;
}
FSOUND_SetOutput(FSOUND_OUTPUT_WINMM);
if (!FSOUND_Init(44100, 32,FSOUND_INIT_GLOBALFOCUS )) return false;//a dll betöltése
return true;

Nézzük a többi függvényt:
bool ZENE::zene_init(int melyik,int hova,bool loop)
{
LPCTSTR nevek[]={"mp3_ogg//o1.ogg","mp3_ogg//z1.mp3","mp3_ogg//o2.ogg","mp3_ogg//z2.mp3"};
if(hova>=MAX_CSATORNA)return false;//nem létező mutató lenne
zenek[hova]=new HOBJ;//új példány létrehozása
zenek[hova]->szam=FSOUND_Sample_Load(FSOUND_FREE,nevek[melyik],loop,0,0);//betöltjük,és visszakapjuk a mutatót
if(zenek[hova]->szam==NULL) return false;
zenek[hova]->csatorna=0,zenek[hova]->pause=false;
return true;
}

A zene_init() függvényt annyiszor hívjuk meg,amennyi számot szeretnénk betölteni.
Bemenő paraméterek magukért beszélnek,a hova jelenti a mutatótömbben elfoglalt helyét.Ez a függvény tölti fel a tömböt létező mutatókkal, de csak  MAX_CSATORNA darabot tudunk betölteni.Mivel nem folyam jellegű ezért betölti az egész zenét a memóriába,eltelik 5-6 másodperc, mire (gondolom kitömöríti) lefut. Jó lenne, ha a MAX_CSATORNA értéke annyi lenne,amennyi nevet megadsz! Létre kell hozni egy új mappát a zenéknek, és nevezd át őket z1 z2 ill ha ogg fájl, akkor o1 o2 stb. 
A bemenőparaméterben a loop true akkor folyamatos lejátszás.


A többi függvény:
void ZENE::zene_stop( int melyik)
{
FSOUND_StopSound(zenek[melyik]->csatorna);//az adott csatornát felszabadítja
//DIRECTSOUNDBUFFER
}
//
void ZENE::zene_hangero(int melyik,int volume)
{
if(!zenek[melyik])return;//ha ide nincs betöltve zene
FSOUND_SetVolume(zenek[melyik]->csatorna,volume);//0-255
}
//
void ZENE::zene_torol(int melyik)
{
if((melyik >= MAX_CSATORNA) | (!zenek[melyik])) return;//ha nem létezik
FSOUND_StopSound(zenek[melyik]->csatorna);
delete zenek[melyik];zenek[melyik]=NULL;

}
//
void ZENE::zene_pause(int melyik,bool paused)
{
if((melyik >= MAX_CSATORNA) | (!zenek[melyik])) return;//ha nem létezik
if(zenek[melyik]->pause==paused)return;//kétszer ne lehessen meghívni
zenek[melyik]->pause=paused;
FSOUND_SetPaused(zenek[melyik]->csatorna,paused);// true= pause
}

#endif

Csak a zene_torol() függvény szorul magyarázatra: Ha már nincs szükség az adott objektumra,akkor előbb illik felszabadítani,mert a lefoglalt memória úgymarad! Azaz ha a "helyére" akarsz tölteni másikat előbb meg kell hívni ezt a függvényt.
egy betöltött zenét többször is le lehet játszani pl visszhang:

zene.zene_play(0);Sleep(200);zene.zene_play(0);

Használata:
A main.cpp-ben törüljél,vagy tedd megjegyzés alá minden Midi szöveget, ha nem akarod azt is egyszerre hallgatni!

#include <Sprite.hpp>
//#include <Midi.hpp>
#include <Ogg_Mp3.hpp>

//
//
//dekralációk
HINSTANCE hinstance;
RAJZ rajz;
INPUT input;
//MIDI midi;
ZENE zene;       
SPRITE sprite;

A zeneszámok betöltése:

sprite.sp_init ();
// midi.midi_init();midi.midi_play();
zene.zene_init(0,0,1);
zene.zene_init(1,1,0);
zene.zene_play(0);zene.zene_hangero(0,255);
zene.zene_play(1);zene.zene_hangero(1,255);

while (fut)

A hangerőt most nem folyamatosan változtatom,hanem csak egyszerű xor művelettel változtatom lenyomott billentyűnél minden 100. képernyőváltáskor: Megírtam a pause használatát is az első zenéhez:
while (fut)
{
/* static int flag=0;//ha a pause függvényt többször hívod, kiakad a progi tehát:
if(input.get_key(DIK_A,true) && !flag){midi.midi_pause(true);flag=1;}
if(input.get_key(DIK_B,true) && flag){midi.midi_pause(false);flag=0;}
if(input.get_key(DIK_C,true)){midi.midi_stop();midi.midi_init(1);midi.midi_play();}*/
//
static int vol1=0x7f,vol2=255,time=100;
if(input.get_key(DIK_H,true))// H betűt lenyomva tartani !!(hangerő váltás a 2 szám között
{
time--;if(time<0)
{
time=100;
vol1 ^=0x80;vol2 ^=0x80;zene.zene_hangero(0,vol1);zene.zene_hangero(1,vol2);
}
}
if(input.get_key(DIK_S,true) ){zene.zene_pause(0,1);}; //S STOP
if(input.get_key(DIK_A,false)){zene.zene_pause(0,0);}; //A START

uzenetkezelo();

Tehát a H betű hangerő váltása a két lejátszott szám között, Az  S a stop és a mellette lévő A  betűre folytatja a lejátszást. Irassuk ki!


uzenetkezelo();
sprite.frissit();
input.get_key(0,true);//csak azért hívjuk meg,hogy az esc-re kilépjen
rajz.kiirbetu("H Hangerő váltás hosszan nyomni!!!",500,10);
rajz.kiirbetu("S STOP első pause",500,30);
rajz.kiirbetu("A Folytatjuk a lejátszást",500,50);
rajz.flip();

}
Azonban ha ezt a szöveget beírod, akkor a Sprite.hpp-ben a frissit() függvényben ki kell venni!!!!

babu_mozgat_m();
babu_mozgat_joy();
// rajz.flip();
Mert ha nem, akkor a sprite osztály rajzol, képet vált, és itt is kiírunk képet váltunk, az eredmény egy kék képernyő és egy rajzolt képernyő, tehát villog!!
Mód van lekérdezni hogy éppen lejátszott-e a szám, vagy nem, de ehhez kéne egy időzítő
lehet csinálni most a képernyő frekvencia alapút (egyszerű számláló)
(Az időzítőkről később) le lehet keverni a hangot stb. Át kell nézni hozzá a fmod.h headert.
Én ezt az osztályt csak egy szám lejátszására használnám,mert az igazi hangeffekteknek ott van a DirectSound hangpuffer,és ez a következő lecke!
U.i.: Azért csatoltam a grafikát is,mert belevettem az egyik ürge mögött menjenek el a sprite-ok!

Ne feledd ! Létre kell hozni a mappát és beletölteni a fájlokat átnevezve a projectben!

itt van a forrás:

vissza: