a9309311d6af71d6f7c64b94c33a013cf9df067c
[blender.git] / intern / audaspace / intern / AUD_SequencerReader.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * Copyright 2009-2011 Jörg Hermann Müller
7  *
8  * This file is part of AudaSpace.
9  *
10  * Audaspace is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * AudaSpace is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Audaspace; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file audaspace/intern/AUD_SequencerReader.cpp
28  *  \ingroup audaspaceintern
29  */
30
31
32 #include "AUD_SequencerReader.h"
33 #include "AUD_Mixer.h"
34
35 #ifdef WITH_SAMPLERATE
36 #include "AUD_SRCResampleReader.h"
37 #else
38 #include "AUD_LinearResampleReader.h"
39 #endif
40 #include "AUD_ChannelMapperReader.h"
41
42 #include <math.h>
43
44 typedef std::list<AUD_Reference<AUD_SequencerStrip> >::iterator AUD_StripIterator;
45 typedef std::list<AUD_Reference<AUD_SequencerEntry> >::iterator AUD_EntryIterator;
46
47 AUD_SequencerReader::AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory,
48                         std::list<AUD_Reference<AUD_SequencerEntry> > &entries, AUD_Specs specs,
49                         void* data, AUD_volumeFunction volume) :
50         m_position(0), m_factory(factory), m_data(data), m_volume(volume)
51 {
52         AUD_DeviceSpecs dspecs;
53         dspecs.specs = specs;
54         dspecs.format = AUD_FORMAT_FLOAT32;
55
56         m_mixer = new AUD_Mixer(dspecs);
57
58         AUD_Reference<AUD_SequencerStrip> strip;
59
60         for(AUD_EntryIterator i = entries.begin(); i != entries.end(); i++)
61         {
62                 strip = new AUD_SequencerStrip;
63                 strip->entry = *i;
64                 strip->old_sound = NULL;
65
66                 m_strips.push_front(strip);
67         }
68 }
69
70 AUD_SequencerReader::~AUD_SequencerReader()
71 {
72         m_factory->removeReader(this);
73 }
74
75 void AUD_SequencerReader::add(AUD_Reference<AUD_SequencerEntry> entry)
76 {
77         AUD_Reference<AUD_SequencerStrip> strip = new AUD_SequencerStrip;
78         strip->entry = entry;
79
80         m_strips.push_front(strip);
81 }
82
83 void AUD_SequencerReader::remove(AUD_Reference<AUD_SequencerEntry> entry)
84 {
85         AUD_Reference<AUD_SequencerStrip> strip;
86         for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
87         {
88                 strip = *i;
89                 if(strip->entry == entry)
90                 {
91                         i++;
92                         m_strips.remove(strip);
93                         return;
94                 }
95         }
96 }
97
98 void AUD_SequencerReader::setSpecs(AUD_Specs specs)
99 {
100         m_mixer->setSpecs(specs);
101
102         AUD_Reference<AUD_SequencerStrip> strip;
103         for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
104         {
105                 strip = *i;
106                 if(!strip->mapper.isNull())
107                 {
108                         strip->mapper->setChannels(specs.channels);
109                         strip->resampler->setRate(specs.rate);
110                 }
111         }
112 }
113
114 bool AUD_SequencerReader::isSeekable() const
115 {
116         return true;
117 }
118
119 void AUD_SequencerReader::seek(int position)
120 {
121         m_position = position;
122 }
123
124 int AUD_SequencerReader::getLength() const
125 {
126         return -1;
127 }
128
129 int AUD_SequencerReader::getPosition() const
130 {
131         return m_position;
132 }
133
134 AUD_Specs AUD_SequencerReader::getSpecs() const
135 {
136         return m_mixer->getSpecs().specs;
137 }
138
139 void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
140 {
141         AUD_DeviceSpecs specs = m_mixer->getSpecs();
142         int rate = specs.rate;
143
144         int start, end, current, skip, len;
145         AUD_Reference<AUD_SequencerStrip> strip;
146         m_buffer.assureSize(length * AUD_SAMPLE_SIZE(specs));
147
148         m_mixer->clear(length);
149
150         if(!m_factory->getMute())
151         {
152                 for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
153                 {
154                         strip = *i;
155                         if(!strip->entry->muted)
156                         {
157                                 if(strip->old_sound != *strip->entry->sound)
158                                 {
159                                         strip->old_sound = *strip->entry->sound;
160
161                                         if(strip->old_sound)
162                                         {
163                                                 try
164                                                 {
165                                                         strip->reader = (*strip->old_sound)->createReader();
166                                                         // resample
167                                                         #ifdef WITH_SAMPLERATE
168                                                                 strip->resampler = new AUD_SRCResampleReader(strip->reader, m_mixer->getSpecs().specs);
169                                                         #else
170                                                                 strip->resampler = new AUD_LinearResampleReader(strip->reader, m_mixer->getSpecs().specs);
171                                                         #endif
172
173                                                         // rechannel
174                                                         strip->mapper = new AUD_ChannelMapperReader(AUD_Reference<AUD_IReader>(strip->resampler), m_mixer->getSpecs().channels);
175                                                 }
176                                                 catch(AUD_Exception)
177                                                 {
178                                                         strip->reader = NULL;
179                                                         strip->resampler = NULL;
180                                                         strip->mapper = NULL;
181                                                 }
182                                         }
183                                         else
184                                         {
185                                                 strip->reader = NULL;
186                                                 strip->resampler = NULL;
187                                                 strip->mapper = NULL;
188                                         }
189                                 }
190
191                                 if(!strip->mapper.isNull())
192                                 {
193                                         end = floor(strip->entry->end * rate);
194                                         if(m_position < end)
195                                         {
196                                                 start = floor(strip->entry->begin * rate);
197                                                 if(m_position + length > start)
198                                                 {
199                                                         current = m_position - start;
200                                                         if(current < 0)
201                                                         {
202                                                                 skip = -current;
203                                                                 current = 0;
204                                                         }
205                                                         else
206                                                                 skip = 0;
207                                                         current += strip->entry->skip * rate;
208                                                         len = length > end - m_position ? end - m_position : length;
209                                                         len -= skip;
210                                                         if(strip->mapper->getPosition() != current)
211                                                                 strip->mapper->seek(current);
212                                                         strip->mapper->read(len, eos, m_buffer.getBuffer());
213                                                         m_mixer->mix(m_buffer.getBuffer(), skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate));
214                                                 }
215                                         }
216                                 }
217                         }
218                 }
219         }
220
221         m_mixer->read((data_t*)buffer, 1.0f);
222
223         m_position += length;
224
225         eos = false;
226 }