1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ultima/nuvie/sound/decoder/random_collection_audio_stream.h"
24 #include "ultima/nuvie/core/game.h"
25 #include "audio/audiostream.h"
26 #include "common/mutex.h"
27 #include "audio/mixer.h"
28 
29 namespace Ultima {
30 namespace Nuvie {
31 namespace U6Audio {
32 
33 #pragma mark -
34 #pragma mark --- random collection audio stream ---
35 #pragma mark -
36 
37 class RandomCollectionAudioStreamImpl : public RandomCollectionAudioStream {
38 private:
39 	/**
40 	 * The sampling rate of this audio stream.
41 	 */
42 	const int _rate;
43 
44 	/**
45 	 * Whether this audio stream is mono (=false) or stereo (=true).
46 	 */
47 	const int _stereo;
48 
49 	/**
50 	 * This flag is set by the finish() method only. See there for more details.
51 	 */
52 	bool _finished;
53 
54 	/**
55 	 * An array of audio streams.
56 	 */
57 	Std::vector<Audio::RewindableAudioStream *> _streams;
58 
59 	DisposeAfterUse::Flag _disposeAfterUse;
60 
61 	Audio::RewindableAudioStream *_currentStream;
62 public:
RandomCollectionAudioStreamImpl(int rate,bool stereo,Std::vector<Audio::RewindableAudioStream * > streams,DisposeAfterUse::Flag disposeAfterUse)63 	RandomCollectionAudioStreamImpl(int rate, bool stereo, Std::vector<Audio::RewindableAudioStream *> streams, DisposeAfterUse::Flag disposeAfterUse)
64 		: _rate(rate), _stereo(stereo), _finished(false), _streams(streams), _disposeAfterUse(disposeAfterUse) {
65 		if (_streams.size() > 0)
66 			_currentStream = _streams[NUVIE_RAND() % _streams.size()];
67 		else
68 			_currentStream = NULL;
69 	}
70 
71 	~RandomCollectionAudioStreamImpl() override;
72 
73 	// Implement the AudioStream API
74 	int readBuffer(int16 *buffer, const int numSamples) override;
isStereo() const75 	bool isStereo() const override {
76 		return _stereo;
77 	}
getRate() const78 	int getRate() const override {
79 		return _rate;
80 	}
endOfData() const81 	bool endOfData() const override {
82 		return false;
83 	}
endOfStream() const84 	bool endOfStream() const override {
85 		return _finished;
86 	}
87 
finish()88 	void finish() override {
89 		_finished = true;
90 	}
91 };
92 
~RandomCollectionAudioStreamImpl()93 RandomCollectionAudioStreamImpl::~RandomCollectionAudioStreamImpl() {
94 	if (_disposeAfterUse == DisposeAfterUse::YES) {
95 		while (!_streams.empty()) {
96 			delete _streams.back();
97 			_streams.pop_back();
98 		}
99 	}
100 }
101 
readBuffer(int16 * buffer,const int numSamples)102 int RandomCollectionAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
103 	int samplesDecoded = 0;
104 
105 	if (_currentStream) {
106 		while (samplesDecoded < numSamples) {
107 			samplesDecoded += _currentStream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
108 
109 			if (_currentStream->endOfData()) {
110 				_currentStream->rewind();
111 
112 				//pseudo random we don't want to play the same stream twice in a row.
113 				int32 idx = NUVIE_RAND() % _streams.size();
114 				Audio::RewindableAudioStream *tmp = _streams[idx];
115 				if (_currentStream == tmp) {
116 					idx = (idx + (NUVIE_RAND() % 1 == 1 ? 1 : _streams.size() - 1)) % _streams.size();
117 					_currentStream = _streams[idx];
118 				} else
119 					_currentStream = tmp;
120 
121 				//DEBUG(0, LEVEL_INFORMATIONAL, "new sample_num = %d\n", idx);
122 			}
123 		}
124 	}
125 	return samplesDecoded;
126 }
127 
makeRandomCollectionAudioStream(int rate,bool stereo,Std::vector<Audio::RewindableAudioStream * > streams,DisposeAfterUse::Flag disposeAfterUse)128 RandomCollectionAudioStream *makeRandomCollectionAudioStream(int rate, bool stereo,
129 		Std::vector<Audio::RewindableAudioStream *> streams, DisposeAfterUse::Flag disposeAfterUse) {
130 	return new RandomCollectionAudioStreamImpl(rate, stereo, streams, disposeAfterUse);
131 }
132 
133 } // End of namespace U6Audio
134 } // End of namespace Nuvie
135 } // End of namespace Ultima
136