Nsound  0.9.4
Mixer.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //
3 // $Id: Mixer.cc 874 2014-09-08 02:21:29Z weegreenblobbie $
4 //
5 // Copyright (c) 2005-2006 Nick Hilton
6 //
7 // weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
8 //
9 //-----------------------------------------------------------------------------
10 
11 //-----------------------------------------------------------------------------
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 //
27 //-----------------------------------------------------------------------------
28 
29 #include <Nsound/AudioStream.h>
30 #include <Nsound/Buffer.h>
31 #include <Nsound/Mixer.h>
32 #include <Nsound/MixerNode.h>
33 #include <Nsound/Nsound.h>
34 
35 #include <iostream>
36 #include <sstream>
37 #include <string.h>
38 
39 using std::cout;
40 using std::endl;
41 using std::flush;
42 
43 using namespace Nsound;
44 
45 //-----------------------------------------------------------------------------
46 Mixer::
48  : max_channels_(0),
49  mixer_set_()
50 {}
51 
52 //-----------------------------------------------------------------------------
53 Mixer::
55 {}
56 
57 void
58 Mixer::
60  float64 first_beat_time,
61  float64 beats_per_minute,
62  const AudioStream & audio_stream)
63 {
64  M_ASSERT_VALUE(first_beat_time, >=, 0.0);
65 
66  if(beats_per_minute < 0.0)
67  {
68  beats_per_minute = 0.0;
69  }
70 
71  MixerNode new_node = MixerNode(
72  first_beat_time, beats_per_minute, audio_stream);
73 
74  mixer_set_.insert(new_node);
75 
76  if(audio_stream.getNChannels() > max_channels_)
77  {
78  max_channels_ = audio_stream.getNChannels();
79  }
80 }
81 
82 void
83 Mixer::
85 {
86  mixer_set_.erase(mixer_set_.begin(), mixer_set_.end());
87 }
88 
90 Mixer::
91 getStream(float64 end_time)
92 {
93  return getStream(0,end_time);
94 }
95 
96 //-----------------------------------------------------------------------------
97 //
98 // Some definitions:
99 //
100 // BPM = beats per minute
101 //
102 // Absolute Mixer view:
103 //
104 // ........[___________]........[___________]........[___________]....
105 // ^ ^ ^ ^
106 // time 0 beat next beat next beat ...
107 //
108 //
109 // Showing start and end times:
110 //
111 // ........[___________]........[___________]........[___________]....
112 // ^ ^
113 // start end
114 //
115 // Prduces and AudioStream:
116 //
117 // ..[___________]........[___________]........[___________]...
118 // ^ ^
119 // start end
120 //
122 Mixer::
124 {
125  M_ASSERT_VALUE(mixer_set_.size(), >, 0);
126  M_ASSERT_VALUE(start_time, <, end_time);
127 
128  if(mixer_set_.size() == 0) return AudioStream(1,1);
129  if(start_time >= end_time) return AudioStream(1,1);
130 
131  MixerSet::const_iterator node = mixer_set_.begin();
132 
133  // Grab the sample rate
134  float64 sample_rate = node->audio_stream_->getSampleRate();
135 
136  // Create the new stream to return. By default it is 2 channels and
137  // has the same sample_rate as the first AudioStream.
138 
139  AudioStream new_stream(sample_rate, max_channels_);
140 
141  // Fill the stream with zeros.
142  uint32 n_samples = static_cast<uint32>(
143  sample_rate * (end_time - start_time));
144 
145  for(uint32 i = 0; i < n_samples; ++i)
146  {
147  new_stream << 0.0;
148  }
149 
150  // Loop through the list of MixerNodes. On each node, loop from start
151  // time to end time and add the node's AudioStream data to new_stream.
152 
153  while(node != mixer_set_.end())
154  {
155  // Beats per minute is a frequency, but we want to calculate the
156  // the time between beats. Remember that f = 1/t, so to get time
157  // we invert the equation, t = 1/f. Here, we also need to multiply
158  // by 60 to get beats per second.
159  //
160  // Therefore, t = 60/f
161 
162  float64 beat_time = 60.0 / node->bpm_;
163 
164  float64 beat_length =
165  static_cast<float64>(node->audio_stream_->getLength())
166  / static_cast<float64>(sample_rate);
167 
168  // We also need to keep track of the next_beat_time and end_time.
169  float64 next_beat_time = node->first_beat_time_;
170  float64 next_end_time = next_beat_time + beat_length;
171 
172  // initialize some indexes
173  uint32 new_stream_offset_index = 0;
174  uint32 node_max_index = node->audio_stream_->getLength();
175 
176  float64 mixer_time = start_time;
177 
178  // Go to the first beat that ends after current time.
179  while(next_end_time < mixer_time)
180  {
181  next_beat_time += beat_time;
182  next_end_time = next_beat_time + beat_length;
183  }
184 
185  float64 new_stream_time = next_beat_time - start_time;
186  float64 new_stream_end_time = end_time - start_time;
187 
188  // Case 1: Start time is before next beat.
189  // ....[________].....[________].....[________]..
190  // ^
191  // start
192 
193  if(mixer_time < next_beat_time)
194  {
195  mixer_time = next_beat_time;
196  }
197 
198  // Case 2: Start time is inside next beat.
199  // ....[________].....[________].....[________]..
200  // ^
201  // start
202 
203  else if(next_beat_time < mixer_time)
204  {
205  // Add the remaing AudioStream to the output.
206 
207  uint32 node_index = static_cast<uint32>((next_end_time - mixer_time) * sample_rate);
208 
209  new_stream_offset_index = static_cast<uint32>(
210  (mixer_time - start_time) * sample_rate);
211 
212  AudioStream temp = node->audio_stream_->substream(node_index);
213 
214  new_stream.add(temp, new_stream_offset_index);
215 
216  next_beat_time += beat_time;
217  next_end_time = next_beat_time + beat_length;
218  mixer_time = next_beat_time;
219  new_stream_time = next_beat_time - start_time;
220  }
221 
222  while(new_stream_time < new_stream_end_time)
223  {
224  new_stream_offset_index = static_cast<uint32>
225  (new_stream_time * sample_rate);
226 
227  // add into new_stream
228  uint32 add_n_samples = node_max_index;
229 
230  if(next_end_time > end_time)
231  {
232  add_n_samples -= static_cast<uint32>((next_end_time - end_time)
233  * static_cast<float64>(sample_rate));
234  }
235 
236  new_stream.add(
237  *node->audio_stream_,
238  new_stream_offset_index,
239  add_n_samples);
240 
241  next_beat_time += beat_time;
242  next_end_time = next_beat_time + beat_length;
243  mixer_time = next_beat_time;
244  new_stream_time += beat_time;
245  }
246 
247  // Move to the next MixerNode in the list.
248  ++node;
249 
250  } // while(node != NULL)
251 
252  return new_stream;
253 }
unsigned int uint32
Definition: Nsound.h:153
#define M_ASSERT_VALUE(a, op, value)
Definition: Macros.h:76
void add(float64 first_beat_time, float64 beats_per_minute, const AudioStream &audio_stream)
This method inserts the AudioStream to the Mixer's LinkList.
Definition: Mixer.cc:59
~Mixer()
Destuctor.
Definition: Mixer.cc:54
Nsound::uint32 max_channels_
Stores the maximum number of channels.
Definition: Mixer.h:124
uint32 getLength() const
Returns the number of samples of audio data in the stream.
Definition: AudioStream.cc:197
AudioStream substream(uint32 start_index, uint32 n_samples=0) const
Definition: AudioStream.cc:825
double float64
Definition: Nsound.h:146
static double start_time
Definition: TicToc.cc:35
Nsound::MixerSet mixer_set_
This stores all the MixerNodes.
Definition: Mixer.h:131
uint32 getNChannels(void) const
Returns the number of audio channels in the stream.
Definition: AudioStream.h:212
AudioStream getStream(float64 end_time)
This method returns one AudioStream composed of all AudioStreams stored in the Mixer's LinkList...
Definition: Mixer.cc:91
Mixer()
Constructor.
Definition: Mixer.cc:47
This class holds the nodes for use with the Mixer class.
Definition: MixerNode.h:55
void clear()
This method removes all streams from the mixer.
Definition: Mixer.cc:84
void add(const AudioStream &as, uint32 offset, uint32 n_samples=0)
This method adds the passed AudioStream to this AudioStream.
Definition: AudioStream.cc:121