3D Audio GSoC:
[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_DefaultMixer.h"
34
35 #include <math.h>
36
37 typedef std::list<AUD_Reference<AUD_SequencerStrip> >::iterator AUD_StripIterator;
38 typedef std::list<AUD_Reference<AUD_SequencerEntry> >::iterator AUD_EntryIterator;
39
40 AUD_SequencerReader::AUD_SequencerReader(AUD_Reference<AUD_SequencerFactory> factory,
41                         std::list<AUD_Reference<AUD_SequencerEntry> > &entries, AUD_Specs specs,
42                         void* data, AUD_volumeFunction volume) :
43         m_position(0), m_factory(factory), m_data(data), m_volume(volume)
44 {
45         AUD_DeviceSpecs dspecs;
46         dspecs.specs = specs;
47         dspecs.format = AUD_FORMAT_FLOAT32;
48
49         m_mixer = new AUD_DefaultMixer(dspecs);
50
51         AUD_Reference<AUD_SequencerStrip> strip;
52
53         for(AUD_EntryIterator i = entries.begin(); i != entries.end(); i++)
54         {
55                 strip = new AUD_SequencerStrip;
56                 strip->entry = *i;
57                 strip->old_sound = NULL;
58
59                 m_strips.push_front(strip);
60         }
61 }
62
63 AUD_SequencerReader::~AUD_SequencerReader()
64 {
65         m_factory->removeReader(this);
66 }
67
68 void AUD_SequencerReader::add(AUD_Reference<AUD_SequencerEntry> entry)
69 {
70         AUD_Reference<AUD_SequencerStrip> strip = new AUD_SequencerStrip;
71         strip->entry = entry;
72
73         m_strips.push_front(strip);
74 }
75
76 void AUD_SequencerReader::remove(AUD_Reference<AUD_SequencerEntry> entry)
77 {
78         AUD_Reference<AUD_SequencerStrip> strip;
79         for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
80         {
81                 strip = *i;
82                 if(strip->entry == entry)
83                 {
84                         i++;
85                         m_strips.remove(strip);
86                         return;
87                 }
88         }
89 }
90
91 bool AUD_SequencerReader::isSeekable() const
92 {
93         return true;
94 }
95
96 void AUD_SequencerReader::seek(int position)
97 {
98         m_position = position;
99 }
100
101 int AUD_SequencerReader::getLength() const
102 {
103         return -1;
104 }
105
106 int AUD_SequencerReader::getPosition() const
107 {
108         return m_position;
109 }
110
111 AUD_Specs AUD_SequencerReader::getSpecs() const
112 {
113         return m_mixer->getSpecs().specs;
114 }
115
116 void AUD_SequencerReader::read(int & length, sample_t* buffer)
117 {
118         AUD_DeviceSpecs specs = m_mixer->getSpecs();
119         int rate = specs.rate;
120
121         int start, end, current, skip, len;
122         AUD_Reference<AUD_SequencerStrip> strip;
123         if(m_buffer.getSize() < length * AUD_SAMPLE_SIZE(specs))
124                 m_buffer.resize(length * AUD_SAMPLE_SIZE(specs));
125
126         m_mixer->clear(length);
127
128         if(!m_factory->getMute())
129         {
130                 for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
131                 {
132                         strip = *i;
133                         if(!strip->entry->muted)
134                         {
135                                 if(strip->old_sound != *strip->entry->sound)
136                                 {
137                                         strip->old_sound = *strip->entry->sound;
138
139                                         if(strip->old_sound)
140                                         {
141                                                 try
142                                                 {
143                                                         strip->reader = m_mixer->prepare((*strip->old_sound)->createReader());
144                                                 }
145                                                 catch(AUD_Exception)
146                                                 {
147                                                         strip->reader = NULL;
148                                                 }
149                                         }
150                                         else
151                                                 strip->reader = NULL;
152                                 }
153
154                                 if(!strip->reader.isNull())
155                                 {
156                                         end = floor(strip->entry->end * rate);
157                                         if(m_position < end)
158                                         {
159                                                 start = floor(strip->entry->begin * rate);
160                                                 if(m_position + length > start)
161                                                 {
162                                                         current = m_position - start;
163                                                         if(current < 0)
164                                                         {
165                                                                 skip = -current;
166                                                                 current = 0;
167                                                         }
168                                                         else
169                                                                 skip = 0;
170                                                         current += strip->entry->skip * rate;
171                                                         len = length > end - m_position ? end - m_position : length;
172                                                         len -= skip;
173                                                         if(strip->reader->getPosition() != current)
174                                                                 strip->reader->seek(current);
175                                                         strip->reader->read(len, m_buffer.getBuffer());
176                                                         m_mixer->mix(m_buffer.getBuffer(), skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate));
177                                                 }
178                                         }
179                                 }
180                         }
181                 }
182         }
183
184         m_mixer->read((data_t*)buffer, 1.0f);
185
186         m_position += length;
187 }