Ottia tuota. Tässä viime kesänä jouduin pakon edessä rustaamaan jonkinlaisen äänentoistosysteemin itselleni pelkkää SDL:ää käyttäen, koska internet ei ollut silloiselta koneelta käytettävissä.
Tässä siis _hyvin_ yksinkertainen äänentoistosysteemi SDL:n perusjuttuja käyttäen; systeemi on erittäin staattinen mutta yksinkertainen käyttää.
Käyttäkää & muokatkaa vapaasti.
audiohandler.c
#ifdef __cplusplus extern "C" { #endif #include <stdio.h> #include <stdlib.h> #include <memory.h> #include "audiohandler.h" /* Tarpeellisia muuttujia */ AudioStruct AUDIO[MAX_MUSIC]; SDL_AudioSpec audiospec; static Uint8 * Audio_Pos, * Audio_Chunk; /* Kutsu tätä systeemiä jossain vaiheessa SDL_Init:n jälkeen */ extern Sint16 InitAudioHandler(void){ Sint16 a; /* Audion alustus (määritelty .h-tiedostossa) */ audiospec.freq = AUDIO_FREQ; audiospec.format = AUDIO_FORM; audiospec.channels = AUDIO_CH; audiospec.samples = 1024; audiospec.callback = HandleAudio; audiospec.userdata = NULL; if(SDL_OpenAudio(&audiospec, NULL) < 0){ printf("Peli mokasi äänten kanssa; %s.\n", SDL_GetError()); return -1; } /* Alusta raidat */ for(a = 0;a < MAX_MUSIC; a++){ AUDIO[a].buf = NULL; AUDIO[a].len = 0; AUDIO[a].pos = 0; AUDIO[a].data = 0; } SDL_PauseAudio(0); return 0; } extern void FreeAudioHandler(void){ Sint16 a; SDL_CloseAudio(); for(a = 0; a < MAX_MUSIC; a++) if(AUDIO[a].buf)free(AUDIO[a].buf); } /* Lataa wav:n tiettyyn musiikkislottiin. */ extern Sint16 LoadWAV(char * n, Sint16 m){ SDL_AudioCVT cvt; SDL_AudioSpec spc; Uint8 * d; Uint32 len; if(SDL_LoadWAV(n, &spc, &d, &len) == NULL){ printf("Virhe tiedoston %s avaamisessa (%s).\n", n, SDL_GetError()); return -1; } /* Rakennetaan CVT... */ SDL_BuildAudioCVT(&cvt, spc.format, spc.channels, spc.freq, AUDIO_FORM, AUDIO_CH, AUDIO_FREQ); /* varaa muistia puskurille käännöksen jälkeen */ cvt.buf = (Uint8*)malloc(len * cvt.len_mult); if(!cvt.buf){ printf("Muistiongelmia äänien (%s) kanssa!.\n", n); SDL_FreeWAV(d); return -1; } /* Tieto talteen ... */ memcpy(cvt.buf, d, len); cvt.len = len; /* Murskaa ja käännä =_= */ SDL_ConvertAudio(&cvt); SDL_FreeWAV(d); /* Tieto talteen rakenteeseen */ AUDIO[m].buf = cvt.buf; AUDIO[m].len = cvt.len_cvt; /* Audio on lopussa. Piste. */ AUDIO[m].pos = AUDIO[m].len; return 0; /* OK! Thumbs up! */ } /* Äänen käsittelijä -_- (yksinkertainen) */ extern void HandleAudio(void * turha, Uint8 * stream, int len){ Sint16 i; Sint32 llen; for(i = 0; i < MAX_MUSIC; i++){ /* Ääntä voidaan vielä lisätä (ainakin toistaiseksi), ellei paussia päällä */ if(AUDIO[i].pos < AUDIO[i].len && !(AUDIO[i].data & AUDIO_PAUSE)){ /* Pituutta vielä jäljellä llen bittiä */ llen = (AUDIO[i].len - AUDIO[i].pos); /* Max. <len> bittiä sekaan */ if(llen>len)llen = len; /* Sekoita raidan data soittettavaan audioon */ SDL_MixAudio(stream, &AUDIO[i].buf[AUDIO[i].pos], llen, SDL_MIX_MAXVOLUME); /* Kohti loppua -_o ... */ AUDIO[i].pos += llen; /* ... jos LOOP päällä, takaisin alkuun. */ if(AUDIO[i].pos == AUDIO[i].len && (AUDIO[i].data & AUDIO_LOOP)) AUDIO[i].pos = 0; } } } /* Aktivoi äänen soitettavaksi >_> */ extern void AddSound(Sint16 m){ AUDIO[m].pos = 0; } /* Laittaa jonkin äänen ikuiselle loopille/pois */ extern void ToggleLooping(Sint16 m){ AUDIO[m].data ^= AUDIO_LOOP; /* Restarttia jos päälle jälleen */ if(AUDIO[m].data & AUDIO_LOOP)AUDIO[m].pos = 0; /* Muuten loppuun => seis */ else AUDIO[m].pos = AUDIO[m].len; } /* Ääni paussille/pois; hyvä esim. taustamusiikin kanssa välillä. */ extern void TogglePause(Sint16 m){ AUDIO[m].data ^= AUDIO_PAUSE; } #ifdef __cplusplus } #endif
audiohandler.h
#ifndef _AUDIOHANDLER_H_ #define _AUDIOHANDLER_H_ #include <SDL/SDL.h> /* Musikaaliset vakiot */ #define MAX_MUSIC 16 /* Montako raitaa max. ? */ #define AUDIO_LOOP 0x1 /* Ikuinen looppi? (taustamusa) */ #define AUDIO_PAUSE 0x2 /* Musiikki paussissa? */ /* Muut liput saatte väsätä itse */ #define AUDIO_FORM AUDIO_S16LSB /* Musiikin formaatti */ #define AUDIO_CH 2 /* Kanavat */ #define AUDIO_FREQ 22050 /* Taajuus (22kHz) */ /* Audiorakenne */ typedef struct{ Uint8 * buf; Sint32 pos, len; Uint8 data; }AudioStruct; /* Aliohjelmien esittelyt */ extern Sint16 InitAudioHandler(void); extern void FreeAudioHandler(void); extern void ToggleLooping(Sint16); extern void TogglePause(Sint16); extern void AddSound(Sint16); extern void HandleAudio(void*, Uint8*, int); extern Sint16 LoadWav(char*, Sint16); #endif /* _AUDIOHANDLER_H_ */
Esimerkkejä käytöstä
/* SDL:n alustukseen SDL_INIT_AUDIO-lippu päälle */ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); /* Jossain alustuksessa seuraava rivi */ InitAudioHandler(); /* Ään(i)en lataaminen tiettyyn muistipaikkaan */ LoadWav("taustamusa.wav", 0); LoadWav("isku.wav", 1); LoadWav("huuto.wav", 2); /* Tietyn äänen aktivointi (soitetaan kerran) */ if(IskeKohdetta())AddSound(1); /* Soita isku.wav */ /* Tietyn äänen (tässä 0) asetus/poisto taustamusiikiksi */ ToggleLooping(0); /* Tietyn äänen asettaminen taukotilaan/pois (0 eli tausta.wav). Eli mikäli tätä kutsuu toistamiseen, musiikki jatkuu siitä mihin se tauolle asetettaessa jäi. */ TogglePause(0); /* Ja ihan lopuksi, vapautus. */ FreeAudioHandler();
Ihan kohtis lyhyt ja selkeä. Tuo äänien säilöminen id:n taakse ei vain ole oiken hyvä idea.. Tee mielummin niin, että palautat pointterin luotuun audio-olioon ja AddSound-funktio ottaisi kyseisen pointterin parametrikseen ääntä soitettaessa.
Jos haluat vältää turhia äänien latauksia, voit pistää rajapinnan taakse std::map-olion, jonka avaimina toimivat äänien nimet. Kun ääni on ladattu, tallennetaan luodun olion pointteri äänen nimen taakse. Jos käyttäjä yrittää luoda ääntä, joka on jo ladattu muistiin, palautetaan käyttäjälle vain jo mapissa oleva osoitin. Muussa tapauksessa luodaan audio, lisätään se mappiin ja palautetaan osoitin käyttäjälle.
Mutta ihan jees viritys.
Tuota kun rustasin, niin en jaksanut alkaa leikkimään pointtereilla sen enempää kuin on pakko. Mutta, toimiihan tuo niinkuin pitääkin >_>
Silti tuo äänien vakio enimmäismäärä ei ole hyväksi. :P Rajapinnan tulee olla joustava! ;)
Totta, mutta sen voi aina muuttaa siihen äänimäärään jota käyttää...
Kyllä sen voisi muokkaista pois jossain vaiheessa.
; ) kamala kiista. Aina voi kehittää järkevämmäksi, mutta toimiihan tuo noin.
En tiedä mikä on pielessä, Bloodshed Dev-Cpp 4.9.9.2
Compiler sanoo:
[Linker error] undefined reference to `InitAudioHandler()' [Linker error] undefined reference to `FreeAudioHandler()' ld returned 1 exit status C:\Ohjelmat\Dev-Cpp\tadaa\Makefile.win [Build Error] ["tadaa] Error 1
Aihe on jo aika vanha, joten et voi enää vastata siihen.