I like having self-contained code, so I'm trying to figure out a way to prevent a sample from playing if it's already playing.
The way the code works, if the player is inside a "hint zone" then the sample plays looped. I want to avoid triggering the sample once, instead using a function like this:
int play_sound(SAMPLE *s, bool looped=false) { if (!s) return 0; else if (****SAMPLE_IS_NOT_PLAYING****) { play_sample(s, 255, 128, 1000, looped); } return 1; }
I searched the forums and found info about voice allocation. it seemed complicated and required external variables. Is there a simple way to do this?
There's a way to do it, but from my research you're going to need that external variable.
It might be best to wrap SAMPLE into a class CSample or something.
Anyway you need to store the voice returned by play_sample. Then run voice_check on that value and see if it == the SAMPLE. If it does, the sample is playing.
EDIT: I can't find a place where SAMPLE::param is used. Does Allegro ever use it? If not you can store the voice in there, that way you won't have to make a CSample or something to contain it.
sample->param = (void *)the_voice;
will only work if sizeof(void *) == sizeof(int)
or instead of wrapping SAMPLE, just wrap a voice.. thats all play_sample does. This way you get greater controll over your sounds.
It works, but it's ghetto:
1 | class sample_wrap_class |
2 | { |
3 | private: |
4 | vector<SAMPLE *> sample; |
5 | vector<int> voice; |
6 | |
7 | public: |
8 | |
9 | void add_pair(SAMPLE *s, int v) |
10 | { |
11 | sample.push_back(s); |
12 | voice.push_back(v); |
13 | } |
14 | |
15 | bool is_playing(SAMPLE *s) |
16 | { |
17 | for (int i=0; i<voice.size(); i++) |
18 | { |
19 | if (sample<i> == s) return voice_check(voice<i>); |
20 | } |
21 | return false; |
22 | } |
23 | |
24 | void remove_reference(SAMPLE *s) |
25 | { |
26 | for (int i=0; i<voice.size(); i++) |
27 | { |
28 | if (sample<i> == s) |
29 | { |
30 | sample.erase(sample.begin() + i); |
31 | voice.erase(voice.begin() + i); |
32 | } |
33 | } |
34 | } |
35 | |
36 | void update() |
37 | { |
38 | for (int i=0; i<voice.size(); i++) |
39 | { |
40 | if (!voice_check(voice<i>)) |
41 | { |
42 | sample.erase(sample.begin() + i); |
43 | voice.erase(voice.begin() + i); |
44 | } |
45 | } |
46 | } |
47 | |
48 | }; |
49 | |
50 | sample_wrap_class sample_wrap; |
51 | |
52 | |
53 | int play_sound(SAMPLE *s, bool looped=false) |
54 | { |
55 | if (!s) |
56 | { |
57 | //allegro_message("error"); |
58 | return 0; |
59 | } |
60 | else |
61 | { |
62 | if (!sample_wrap.is_playing(s)) |
63 | { |
64 | int v = play_sample(s, 255, 128, 1000, looped); |
65 | sample_wrap.add_pair(s, v); |
66 | } |
67 | } |
68 | } |
69 | |
70 | int stop_sound(SAMPLE *s) |
71 | { |
72 | if (!s) return 0; |
73 | else stop_sample(s); |
74 | } |
[edit]reply for cookies
Better than nothin'.
[edit]Ignore this, I spewed out a whole set of code for using the voice functions and managing them via timers, etc without realising that wasn't the question. So I've deleted it.
Neil: What was the code all about? I'm interested.
You'll have to fill in the gaps yourself and ignore the class prefix, but...
you'll need these and set your own nice values
#define TIMER_DIGIPURGETIME 5000
#define MAXSOUNDS 32
int VoiceArray[MAXSOUNDS]; //maximum allowed voices
and maybe this somewhere:
install_int(TimerDigiPurgeNow,TIMER_DIGIPURGETIME); void TimerDigiPurgeNow() { //music handler for purging stuff //automatically deallocates sounds that have stopped playing //called every 5 seconds, which seems reasonable to me TimerDigiPurge=true; } END_OF_FUNCTION(TimerDigiPurgeNow);
Then in your timer looper say,
if(TimerDigiPurge) { SoundPurgeDigi(false); TimerDigiPurge=false;}
1 | int Framework::SoundPlayDigi(DATAFILE* df, int samplenum,int loopflag,int vol) |
2 | { |
3 | if(vol==0) return -1; |
4 | else |
5 | { |
6 | return SoundPlayDigi((SAMPLE*)df[samplenum].dat,vol,loopflag); |
7 | } |
8 | } |
9 | |
10 | int Framework::SoundPlayDigi(SAMPLE* samp, int vol, int loopflag) |
11 | { |
12 | int ret=-1; //default which is could not play |
13 | |
14 | if(vol==-1) vol=GameConfiguration->CapsSound.SampleVolume; |
15 | if(vol>255 || vol<0) vol=255; |
16 | |
17 | if(GameConfiguration->CapsActualSystem.UseSound && vol!=0) |
18 | { |
19 | |
20 | //allocate a voice if possible |
21 | ret=allocate_voice(samp); |
22 | if(ret!=-1) |
23 | { |
24 | //if available add to list and play - see purgedigi/stopdigi |
25 | //may fail to add if system removes a lower priority voice |
26 | //until the purgedigi is called |
27 | //hopefully |
28 | //set sample priority |
29 | voice_set_playmode(ret,loopflag); |
30 | voice_set_volume(ret, vol); |
31 | voice_start(ret); |
32 | |
33 | //go through the voice array and deallocate voice if being stored |
34 | for(int i=0;i<GameConfiguration->CapsSound.MaxSounds;i++) |
35 | { |
36 | if(VoiceArray<i>==-1) |
37 | { |
38 | VoiceArray<i>=ret; |
39 | break; |
40 | } |
41 | } |
42 | } |
43 | } |
44 | return ret; |
45 | } |
46 | |
47 | void Framework::SoundStopDigi(int voice,bool force) |
48 | { |
49 | //stop a digi playing, for example if in a loop |
50 | if(voice<0 && GameConfiguration->CapsActualSystem.UseSound) |
51 | { |
52 | if(force==true) deallocate_voice(voice); |
53 | else release_voice(voice); //allow it to finish first |
54 | |
55 | //go through the voice array and deallocate voice if being stored |
56 | for(int i=0;i<GameConfiguration->CapsSound.MaxSounds;i++) |
57 | { |
58 | if(VoiceArray<i>==voice) |
59 | { |
60 | VoiceArray<i>=-1; |
61 | break; |
62 | } |
63 | } |
64 | } |
65 | } |
66 | |
67 | void Framework::SoundPurgeDigi(bool killit) |
68 | { |
69 | //go through the voice array and deallocate voices |
70 | //this is used to stop the user from having to do stopdigi |
71 | // to speed up call it on a timer rather than, say, every frame |
72 | // the game loop will do this for us automatically |
73 | int pos; |
74 | assert(GameConfiguration->CapsSound.MaxSounds<255); |
75 | |
76 | if(GameConfiguration->CapsActualSystem.UseSound) |
77 | { |
78 | //loop through array |
79 | for(int i=0;i<GameConfiguration->CapsSound.MaxSounds;i++) |
80 | { |
81 | //if it contains a voice get its position |
82 | if(VoiceArray<i>!=-1) pos=voice_get_position(VoiceArray<i>); else pos=-2; |
83 | |
84 | //if it is at the end then release it |
85 | if(pos==-1 || (killit==true && pos!=-2)) |
86 | { |
87 | deallocate_voice(VoiceArray<i>); |
88 | VoiceArray<i>=-1; |
89 | } |
90 | } |
91 | } |
92 | } |
93 | |
94 | void Framework::SoundKillDigi() |
95 | { |
96 | //stop all samples in their tracks and clear the play buffer |
97 | if(GameConfiguration->CapsActualSystem.UseSound) |
98 | { |
99 | //loop through array |
100 | for(int i=0;i<GameConfiguration->CapsSound.MaxSounds;i++) |
101 | { |
102 | //if it contains a voice get its position |
103 | if(VoiceArray<i>!=-1) deallocate_voice(VoiceArray<i>); |
104 | VoiceArray<i>=-1; |
105 | } |
106 | } |
107 | } |
108 | |
109 | int Framework::SoundDigiPos(int voice) |
110 | { |
111 | if(GameConfiguration->CapsActualSystem.UseSound && voice>=0) return voice_get_position(voice); |
112 | else return -1; |
113 | } |