diff options
author | Joerg Mueller <nexyon@gmail.com> | 2010-02-08 02:41:17 +0300 |
---|---|---|
committer | Joerg Mueller <nexyon@gmail.com> | 2010-02-08 02:41:17 +0300 |
commit | 9827a3e9eac70f68db6dc16d03016c51b7ece3f0 (patch) | |
tree | 8825b454008d3b97a64018884c179ea94874af44 /intern | |
parent | 2f72b91a54faa7cfbdfd97eff608c8911df1d221 (diff) |
2.5 Audio:
- recode of the whole sequencer audio handling
- encode audio flag removed, instead you choose None as audio codec, added None for video codec too
- ffmpeg formats/codecs: enabled: theora, ogg, vorbis; added: matroska, flac (not working, who can fix?), mp3, wav
- sequencer wave drawing
- volume animation (now also working when mixing down to a file!)
- made sequencer strip position and length values unanimatable
Diffstat (limited to 'intern')
-rw-r--r-- | intern/audaspace/FX/AUD_LoopReader.cpp | 9 | ||||
-rw-r--r-- | intern/audaspace/FX/AUD_LoopReader.h | 5 | ||||
-rw-r--r-- | intern/audaspace/OpenAL/AUD_OpenALDevice.cpp | 13 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_C-API.cpp | 109 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_C-API.h | 29 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_Mixer.cpp | 12 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_Mixer.h | 9 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_SequencerFactory.cpp | 109 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_SequencerFactory.h | 77 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_SequencerReader.cpp | 245 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_SequencerReader.h | 102 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_SoftwareDevice.cpp | 9 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_Space.h | 6 |
13 files changed, 707 insertions, 27 deletions
diff --git a/intern/audaspace/FX/AUD_LoopReader.cpp b/intern/audaspace/FX/AUD_LoopReader.cpp index 7d70fc20221..3bcd8c2f9d3 100644 --- a/intern/audaspace/FX/AUD_LoopReader.cpp +++ b/intern/audaspace/FX/AUD_LoopReader.cpp @@ -31,6 +31,7 @@ AUD_LoopReader::AUD_LoopReader(AUD_IReader* reader, int loop) : AUD_EffectReader(reader), m_loop(loop) { + m_samples = -1; m_buffer = new AUD_Buffer(); AUD_NEW("buffer") } @@ -51,6 +52,7 @@ bool AUD_LoopReader::notify(AUD_Message &message) if(message.type == AUD_MSG_LOOP) { m_loop = message.loopcount; + m_samples = message.time * m_reader->getSpecs().rate; m_reader->notify(message); @@ -64,6 +66,13 @@ void AUD_LoopReader::read(int & length, sample_t* & buffer) AUD_Specs specs = m_reader->getSpecs(); int samplesize = AUD_SAMPLE_SIZE(specs); + if(m_samples >= 0) + { + if(length > m_samples) + length = m_samples; + m_samples -= length; + } + int len = length; m_reader->read(len, buffer); diff --git a/intern/audaspace/FX/AUD_LoopReader.h b/intern/audaspace/FX/AUD_LoopReader.h index 621ee3493ab..e61a49cb0db 100644 --- a/intern/audaspace/FX/AUD_LoopReader.h +++ b/intern/audaspace/FX/AUD_LoopReader.h @@ -46,6 +46,11 @@ private: */ int m_loop; + /** + * The left samples. + */ + int m_samples; + public: /** * Creates a new loop reader. diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp index 0b3e86eda56..9e153b9b34f 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp @@ -180,7 +180,7 @@ void AUD_OpenALDevice::updateStreams() AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate); - if(alGetError() != AL_NO_ERROR) + if((err = alGetError()) != AL_NO_ERROR) { sound->data_end = true; break; @@ -839,13 +839,14 @@ bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position) if(info != AL_PLAYING) { - if(info != AL_STOPPED) + if(info == AL_PAUSED) alSourceStop(alhandle->source); - alSourceUnqueueBuffers(alhandle->source, - AUD_OPENAL_CYCLE_BUFFERS, - alhandle->buffers); - if(alGetError() == AL_NO_ERROR) + alSourcei(alhandle->source, AL_BUFFER, 0); + alhandle->current = 0; + + ALenum err; + if((err = alGetError()) == AL_NO_ERROR) { sample_t* buf; int length; diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index b7d0183cb5e..b363c4576b3 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -25,6 +25,7 @@ #include <cstdlib> #include <cstring> +#include <cmath> #include "AUD_NULLDevice.h" #include "AUD_I3DDevice.h" @@ -47,6 +48,7 @@ #include "AUD_ReadDevice.h" #include "AUD_SourceCaps.h" #include "AUD_IReader.h" +#include "AUD_SequencerFactory.h" #ifdef WITH_SDL #include "AUD_SDLDevice.h" @@ -231,7 +233,7 @@ AUD_Sound* AUD_delaySound(AUD_Sound* sound, float delay) } } -extern AUD_Sound* AUD_limitSound(AUD_Sound* sound, float start, float end) +AUD_Sound* AUD_limitSound(AUD_Sound* sound, float start, float end) { assert(sound); @@ -273,13 +275,14 @@ AUD_Sound* AUD_loopSound(AUD_Sound* sound) } } -int AUD_stopLoop(AUD_Handle* handle) +int AUD_setLoop(AUD_Handle* handle, int loops, float time) { if(handle) { AUD_Message message; message.type = AUD_MSG_LOOP; - message.loopcount = 0; + message.loopcount = loops; + message.time = time; try { @@ -537,14 +540,16 @@ AUD_Device* AUD_openReadDevice(AUD_DeviceSpecs specs) } } -AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound) +AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek) { assert(device); assert(sound); try { - return device->play(sound); + AUD_Handle* handle = device->play(sound); + device->seek(handle, seek); + return handle; } catch(AUD_Exception) { @@ -663,3 +668,97 @@ float* AUD_readSoundBuffer(const char* filename, float low, float high, *length = position; return result; } + +AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume) +{ + if(AUD_device) + { + return new AUD_SequencerFactory(AUD_device->getSpecs().specs, data, volume); + } + else + { + AUD_Specs specs; + specs.channels = AUD_CHANNELS_STEREO; + specs.rate = AUD_RATE_44100; + return new AUD_SequencerFactory(specs, data, volume); + } +} + +void AUD_destroySequencer(AUD_Sound* sequencer) +{ + delete ((AUD_SequencerFactory*)sequencer); +} + +AUD_SequencerEntry* AUD_addSequencer(AUD_Sound** sequencer, AUD_Sound* sound, + float begin, float end, float skip, void* data) +{ + return ((AUD_SequencerFactory*)sequencer)->add((AUD_IFactory**) sound, begin, end, skip, data); +} + +void AUD_removeSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry) +{ + ((AUD_SequencerFactory*)sequencer)->remove(entry); +} + +void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, + float begin, float end, float skip) +{ + ((AUD_SequencerFactory*)sequencer)->move(entry, begin, end, skip); +} + +void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, char mute) +{ + ((AUD_SequencerFactory*)sequencer)->mute(entry, mute); +} + +int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length) +{ + AUD_IReader* reader = sound->createReader(); + AUD_DeviceSpecs specs; + sample_t* buf; + + specs.specs = reader->getSpecs(); + specs.channels = AUD_CHANNELS_MONO; + specs.format = AUD_FORMAT_FLOAT32; + + AUD_ChannelMapperFactory mapper(reader, specs); + + if(!reader || reader->getType() != AUD_TYPE_BUFFER) + return -1; + + reader = mapper.createReader(); + + if(!reader) + return -1; + + int len = reader->getLength(); + float samplejump = (float)len / (float)length; + float min, max; + + for(int i = 0; i < length; i++) + { + len = floor(samplejump * (i+1)) - floor(samplejump * i); + reader->read(len, buf); + + if(len < 1) + { + length = i; + break; + } + + max = min = *buf; + for(int j = 1; j < len; j++) + { + if(buf[j] < min) + min = buf[j]; + if(buf[j] > max) + max = buf[j]; + buffer[i * 2] = min; + buffer[i * 2 + 1] = max; + } + } + + delete reader; AUD_DELETE("reader") + + return length; +} diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index c3439f89ade..ce1791886de 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -50,6 +50,8 @@ typedef struct typedef void AUD_Sound; typedef void AUD_Handle; typedef void AUD_Device; + typedef void AUD_SequencerEntry; + typedef float (*AUD_volumeFunction)(void*, void*, float); #endif /** @@ -143,11 +145,13 @@ extern AUD_Sound* AUD_pingpongSound(AUD_Sound* sound); extern AUD_Sound* AUD_loopSound(AUD_Sound* sound); /** - * Stops a looping sound when the current playback finishes. + * Sets a remaining loop count of a looping sound that currently plays. * \param handle The playback handle. + * \param loops The count of remaining loops, -1 for infinity. + * \param time The time after which playback should stop, -1 for infinity. * \return Whether the handle is valid. */ -extern int AUD_stopLoop(AUD_Handle* handle); +extern int AUD_setLoop(AUD_Handle* handle, int loops, float time); /** * Rectifies a sound. @@ -211,6 +215,7 @@ extern int AUD_seek(AUD_Handle* handle, float seekTo); /** * Retrieves the playback position of a handle. + * \param handle The handle to the sound. * \return The current playback position in seconds or 0.0 if the handle is * invalid. */ @@ -318,9 +323,10 @@ extern int AUD_setDeviceVolume(AUD_Device* device, float volume); * Plays back a sound file through a read device. * \param device The read device. * \param sound The handle of the sound file. + * \param seek The position where the sound should be seeked to. * \return A handle to the played back sound. */ -extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound); +extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek); /** * Sets the volume of a played back sound of a read device. @@ -360,6 +366,23 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high, float sthreshold, int samplerate, int* length); +extern AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume); + +extern void AUD_destroySequencer(AUD_Sound* sequencer); + +extern AUD_SequencerEntry* AUD_addSequencer(AUD_Sound** sequencer, AUD_Sound* sound, + float begin, float end, float skip, void* data); + +extern void AUD_removeSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry); + +extern void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, + float begin, float end, float skip); + +extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, + char mute); + +extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length); + #ifdef __cplusplus } #endif diff --git a/intern/audaspace/intern/AUD_Mixer.cpp b/intern/audaspace/intern/AUD_Mixer.cpp index bddc719b179..299388b558b 100644 --- a/intern/audaspace/intern/AUD_Mixer.cpp +++ b/intern/audaspace/intern/AUD_Mixer.cpp @@ -68,6 +68,11 @@ AUD_IReader* AUD_Mixer::prepare(AUD_IReader* reader) return reader; } +AUD_DeviceSpecs AUD_Mixer::getSpecs() +{ + return m_specs; +} + void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs) { m_specs = specs; @@ -115,10 +120,11 @@ void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs) } } -void AUD_Mixer::add(sample_t* buffer, int length, float volume) +void AUD_Mixer::add(sample_t* buffer, int start, int length, float volume) { AUD_MixerBuffer buf; buf.buffer = buffer; + buf.start = start; buf.length = length; buf.volume = volume; m_buffers.push_back(buf); @@ -145,11 +151,11 @@ void AUD_Mixer::superpose(data_t* buffer, int length, float volume) buf = m_buffers.front(); m_buffers.pop_front(); - end = buf.length*channels; + end = buf.length * channels; in = buf.buffer; for(int i = 0; i < end; i++) - out[i] += in[i]*buf.volume * volume; + out[i + buf.start * channels] += in[i] * buf.volume * volume; } m_convert(buffer, (data_t*) out, length * channels); diff --git a/intern/audaspace/intern/AUD_Mixer.h b/intern/audaspace/intern/AUD_Mixer.h index 5097b9ec2a6..5dcdef45eba 100644 --- a/intern/audaspace/intern/AUD_Mixer.h +++ b/intern/audaspace/intern/AUD_Mixer.h @@ -37,6 +37,7 @@ class AUD_IReader; struct AUD_MixerBuffer { sample_t* buffer; + int start; int length; float volume; }; @@ -99,6 +100,12 @@ public: AUD_IReader* prepare(AUD_IReader* reader); /** + * Returns the target specification for superposing. + * \return The target specification. + */ + AUD_DeviceSpecs getSpecs(); + + /** * Sets the target specification for superposing. * \param specs The target specification. */ @@ -111,7 +118,7 @@ public: * \param length The length of the buffer in samples. * \param volume The mixing volume. Must be a value between 0.0 and 1.0. */ - void add(sample_t* buffer, int length, float volume); + void add(sample_t* buffer, int start, int length, float volume); /** * Superposes all added buffers into an output buffer. diff --git a/intern/audaspace/intern/AUD_SequencerFactory.cpp b/intern/audaspace/intern/AUD_SequencerFactory.cpp new file mode 100644 index 00000000000..bb5cf27fb5f --- /dev/null +++ b/intern/audaspace/intern/AUD_SequencerFactory.cpp @@ -0,0 +1,109 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 Jörg Hermann Müller + * + * This file is part of AudaSpace. + * + * AudaSpace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AudaSpace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>. + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#include "AUD_SequencerFactory.h" +#include "AUD_SequencerReader.h" + +typedef std::list<AUD_SequencerReader*>::iterator AUD_ReaderIterator; + +AUD_SequencerFactory::AUD_SequencerFactory(AUD_Specs specs, void* data, AUD_volumeFunction volume) +{ + m_specs = specs; + m_data = data; + m_volume = volume; +} + +AUD_SequencerFactory::~AUD_SequencerFactory() +{ + AUD_SequencerReader* reader; + AUD_SequencerEntry* entry; + + while(!m_readers.empty()) + { + reader = m_readers.front(); + m_readers.pop_front(); + reader->destroy(); + } + + while(!m_entries.empty()) + { + entry = m_entries.front(); + m_entries.pop_front(); + delete entry; AUD_DELETE("seqentry") + } +} + +AUD_SequencerEntry* AUD_SequencerFactory::add(AUD_IFactory** sound, float begin, float end, float skip, void* data) +{ + AUD_SequencerEntry* entry = new AUD_SequencerEntry; AUD_NEW("seqentry") + entry->sound = sound; + entry->begin = begin; + entry->skip = skip; + entry->end = end; + entry->muted = false; + entry->data = data; + + m_entries.push_front(entry); + + for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++) + (*i)->add(entry); + + return entry; +} + +void AUD_SequencerFactory::remove(AUD_SequencerEntry* entry) +{ + for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++) + (*i)->remove(entry); + + m_entries.remove(entry); + + delete entry; AUD_DELETE("seqentry") +} + +void AUD_SequencerFactory::move(AUD_SequencerEntry* entry, float begin, float end, float skip) +{ + entry->begin = begin; + entry->skip = skip; + entry->end = end; +} + +void AUD_SequencerFactory::mute(AUD_SequencerEntry* entry, bool mute) +{ + entry->muted = mute; +} + +AUD_IReader* AUD_SequencerFactory::createReader() +{ + AUD_SequencerReader* reader = new AUD_SequencerReader(this, m_entries, m_specs, m_data, m_volume); AUD_NEW("reader") + m_readers.push_front(reader); + + return reader; +} + +void AUD_SequencerFactory::removeReader(AUD_SequencerReader* reader) +{ + m_readers.remove(reader); +} diff --git a/intern/audaspace/intern/AUD_SequencerFactory.h b/intern/audaspace/intern/AUD_SequencerFactory.h new file mode 100644 index 00000000000..b564c888fc6 --- /dev/null +++ b/intern/audaspace/intern/AUD_SequencerFactory.h @@ -0,0 +1,77 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 Jörg Hermann Müller + * + * This file is part of AudaSpace. + * + * AudaSpace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AudaSpace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>. + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#ifndef AUD_SEQUENCERFACTORY +#define AUD_SEQUENCERFACTORY + +#include "AUD_IFactory.h" + +#include <list> + +typedef float (*AUD_volumeFunction)(void*, void*, float); + +struct AUD_SequencerEntry +{ + AUD_IFactory** sound; + float begin; + float end; + float skip; + bool muted; + void* data; +}; + +class AUD_SequencerReader; + +/** + * This factory creates a resampling reader that does simple linear resampling. + */ +class AUD_SequencerFactory : public AUD_IFactory +{ +private: + /** + * The target specification. + */ + AUD_Specs m_specs; + + std::list<AUD_SequencerEntry*> m_entries; + std::list<AUD_SequencerReader*> m_readers; + void* m_data; + AUD_volumeFunction m_volume; + +public: + AUD_SequencerFactory(AUD_Specs specs, void* data, AUD_volumeFunction volume); + ~AUD_SequencerFactory(); + + AUD_SequencerEntry* add(AUD_IFactory** sound, float begin, float end, float skip, void* data); + void remove(AUD_SequencerEntry* entry); + void move(AUD_SequencerEntry* entry, float begin, float end, float skip); + void mute(AUD_SequencerEntry* entry, bool mute); + + virtual AUD_IReader* createReader(); + + void removeReader(AUD_SequencerReader* reader); +}; + +#endif //AUD_SEQUENCERFACTORY diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp new file mode 100644 index 00000000000..84c14762893 --- /dev/null +++ b/intern/audaspace/intern/AUD_SequencerReader.cpp @@ -0,0 +1,245 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 Jörg Hermann Müller + * + * This file is part of AudaSpace. + * + * AudaSpace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AudaSpace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>. + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#include "AUD_SequencerReader.h" +#include "AUD_Buffer.h" + +#include <math.h> + +typedef std::list<AUD_SequencerStrip*>::iterator AUD_StripIterator; +typedef std::list<AUD_SequencerEntry*>::iterator AUD_EntryIterator; + +AUD_SequencerReader::AUD_SequencerReader(AUD_SequencerFactory* factory, std::list<AUD_SequencerEntry*> &entries, AUD_Specs specs, void* data, AUD_volumeFunction volume) +{ + AUD_DeviceSpecs dspecs; + dspecs.specs = specs; + dspecs.format = AUD_FORMAT_FLOAT32; + + m_mixer.setSpecs(dspecs); + m_factory = factory; + m_data = data; + m_volume = volume; + + AUD_SequencerStrip* strip; + + for(AUD_EntryIterator i = entries.begin(); i != entries.end(); i++) + { + strip = new AUD_SequencerStrip; AUD_NEW("seqstrip") + strip->entry = *i; + strip->old_sound = NULL; + + if(strip->old_sound) + strip->reader = m_mixer.prepare(strip->old_sound->createReader()); + else + strip->reader = NULL; + + m_strips.push_front(strip); + } + + m_position = 0; + m_buffer = new AUD_Buffer(); AUD_NEW("buffer") +} + +AUD_SequencerReader::~AUD_SequencerReader() +{ + if(m_factory != NULL) + m_factory->removeReader(this); + + AUD_SequencerStrip* strip; + + while(!m_strips.empty()) + { + strip = m_strips.front(); + m_strips.pop_front(); + if(strip->reader) + { + delete strip->reader; AUD_DELETE("reader") + } + delete strip; AUD_DELETE("seqstrip") + } + + delete m_buffer; AUD_DELETE("buffer") +} + +void AUD_SequencerReader::destroy() +{ + m_factory = NULL; + AUD_SequencerStrip* strip; + + while(!m_strips.empty()) + { + strip = m_strips.front(); + m_strips.pop_front(); + delete strip; AUD_DELETE("seqstrip") + } +} + +void AUD_SequencerReader::add(AUD_SequencerEntry* entry) +{ + AUD_SequencerStrip* strip = new AUD_SequencerStrip; AUD_NEW("seqstrip") + strip->entry = entry; + strip->old_sound = NULL; + + if(strip->old_sound) + strip->reader = m_mixer.prepare(strip->old_sound->createReader()); + else + strip->reader = NULL; + + m_strips.push_front(strip); +} + +void AUD_SequencerReader::remove(AUD_SequencerEntry* entry) +{ + AUD_SequencerStrip* strip; + for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++) + { + strip = *i; + if(strip->entry == entry) + { + i++; + if(strip->reader) + { + delete strip->reader; AUD_DELETE("reader") + } + m_strips.remove(strip); + delete strip; + return; + } + } +} + +bool AUD_SequencerReader::isSeekable() +{ + return true; +} + +void AUD_SequencerReader::seek(int position) +{ + m_position = position; +} + +int AUD_SequencerReader::getLength() +{ + return -1; +} + +int AUD_SequencerReader::getPosition() +{ + return m_position; +} + +AUD_Specs AUD_SequencerReader::getSpecs() +{ + return m_mixer.getSpecs().specs; +} + +AUD_ReaderType AUD_SequencerReader::getType() +{ + return AUD_TYPE_STREAM; +} + +bool AUD_SequencerReader::notify(AUD_Message &message) +{ + bool result = false; + AUD_SequencerStrip* strip; + + for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++) + { + strip = *i; + if(strip->reader) + result |= (*i)->reader->notify(message); + } + + return result; +} + +void AUD_SequencerReader::read(int & length, sample_t* & buffer) +{ + AUD_DeviceSpecs specs = m_mixer.getSpecs(); + int samplesize = AUD_SAMPLE_SIZE(specs); + int rate = specs.rate; + + int size = length * samplesize; + + int start, end, current, skip, len; + AUD_SequencerStrip* strip; + sample_t* buf; + + if(m_buffer->getSize() < size) + m_buffer->resize(size); + buffer = m_buffer->getBuffer(); + + for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++) + { + strip = *i; + if(!strip->entry->muted) + { + if(strip->old_sound != *strip->entry->sound) + { + strip->old_sound = *strip->entry->sound; + if(strip->reader) + { + delete strip->reader; AUD_DELETE("reader") + } + + if(strip->old_sound) + strip->reader = m_mixer.prepare(strip->old_sound->createReader()); + else + strip->reader = NULL; + } + + if(strip->reader) + { + end = floor(strip->entry->end * rate); + if(m_position < end) + { + start = floor(strip->entry->begin * rate); + if(m_position + length > start) + { + current = m_position - start; + if(current < 0) + { + skip = -current; + current = 0; + } + else + skip = 0; + current += strip->entry->skip * rate; + len = length > end - m_position ? end - m_position : length; + len -= skip; + if(strip->reader->getPosition() != current) + strip->reader->seek(current); + strip->reader->read(len, buf); + m_mixer.add(buf, skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate)); + } + } + } + } + } + + m_mixer.superpose((data_t*)buffer, length, 1.0f); + + m_position += length; +} diff --git a/intern/audaspace/intern/AUD_SequencerReader.h b/intern/audaspace/intern/AUD_SequencerReader.h new file mode 100644 index 00000000000..a50e1642260 --- /dev/null +++ b/intern/audaspace/intern/AUD_SequencerReader.h @@ -0,0 +1,102 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 Jörg Hermann Müller + * + * This file is part of AudaSpace. + * + * AudaSpace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AudaSpace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>. + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#ifndef AUD_SEQUENCERREADER +#define AUD_SEQUENCERREADER + +#include "AUD_IReader.h" +#include "AUD_SequencerFactory.h" +#include "AUD_Mixer.h" + +class AUD_Buffer; + +struct AUD_SequencerStrip +{ + AUD_IFactory* old_sound; + AUD_IReader* reader; + AUD_SequencerEntry* entry; +}; + +/** + * This resampling reader uses libsamplerate for resampling. + */ +class AUD_SequencerReader : public AUD_IReader +{ +private: + /** + * The current position. + */ + int m_position; + + /** + * The sound output buffer. + */ + AUD_Buffer *m_buffer; + + /** + * The target specification. + */ + AUD_Mixer m_mixer; + + /** + * Saves the SequencerFactory the reader belongs to. + */ + AUD_SequencerFactory* m_factory; + + std::list<AUD_SequencerStrip*> m_strips; + + void* m_data; + AUD_volumeFunction m_volume; + +public: + /** + * Creates a resampling reader. + * \param reader The reader to mix. + * \param specs The target specification. + * \exception AUD_Exception Thrown if the reader is NULL. + */ + AUD_SequencerReader(AUD_SequencerFactory* factory, std::list<AUD_SequencerEntry*> &entries, AUD_Specs specs, void* data, AUD_volumeFunction volume); + + /** + * Destroys the reader. + */ + ~AUD_SequencerReader(); + + void destroy(); + + void add(AUD_SequencerEntry* entry); + void remove(AUD_SequencerEntry* entry); + + virtual bool isSeekable(); + virtual void seek(int position); + virtual int getLength(); + virtual int getPosition(); + virtual AUD_Specs getSpecs(); + virtual AUD_ReaderType getType(); + virtual bool notify(AUD_Message &message); + virtual void read(int & length, sample_t* & buffer); +}; + +#endif //AUD_SEQUENCERREADER diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index a615bcd0245..5a3f25fba07 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -100,7 +100,6 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) AUD_SoftwareHandle* sound; int len; sample_t* buf; - int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs); std::list<AUD_SoftwareHandle*> stopSounds; // for all sounds @@ -116,7 +115,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) len = length; sound->reader->read(len, buf); - m_mixer->add(buf, len, sound->volume); + m_mixer->add(buf, 0, len, sound->volume); // in case the end of the sound is reached if(len < length) @@ -128,12 +127,6 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) } } - // fill with silence - if(m_specs.format == AUD_FORMAT_U8) - memset(buffer, 0x80, length * sample_size); - else - memset(buffer, 0, length * sample_size); - // superpose m_mixer->superpose(buffer, length, m_volume); diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h index 1d60be3979b..9e192ac2cac 100644 --- a/intern/audaspace/intern/AUD_Space.h +++ b/intern/audaspace/intern/AUD_Space.h @@ -294,7 +294,11 @@ typedef struct union { // loop reader - int loopcount; + struct + { + int loopcount; + float time; + }; // volume reader float volume; |