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
This commit is contained in:
@@ -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);
|
||||
|
@@ -46,6 +46,11 @@ private:
|
||||
*/
|
||||
int m_loop;
|
||||
|
||||
/**
|
||||
* The left samples.
|
||||
*/
|
||||
int m_samples;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new loop reader.
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -37,6 +37,7 @@ class AUD_IReader;
|
||||
struct AUD_MixerBuffer
|
||||
{
|
||||
sample_t* buffer;
|
||||
int start;
|
||||
int length;
|
||||
float volume;
|
||||
};
|
||||
@@ -98,6 +99,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.
|
||||
|
109
intern/audaspace/intern/AUD_SequencerFactory.cpp
Normal file
109
intern/audaspace/intern/AUD_SequencerFactory.cpp
Normal file
@@ -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);
|
||||
}
|
77
intern/audaspace/intern/AUD_SequencerFactory.h
Normal file
77
intern/audaspace/intern/AUD_SequencerFactory.h
Normal file
@@ -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
|
245
intern/audaspace/intern/AUD_SequencerReader.cpp
Normal file
245
intern/audaspace/intern/AUD_SequencerReader.cpp
Normal file
@@ -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;
|
||||
}
|
102
intern/audaspace/intern/AUD_SequencerReader.h
Normal file
102
intern/audaspace/intern/AUD_SequencerReader.h
Normal file
@@ -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
|
@@ -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);
|
||||
|
||||
|
@@ -294,7 +294,11 @@ typedef struct
|
||||
union
|
||||
{
|
||||
// loop reader
|
||||
int loopcount;
|
||||
struct
|
||||
{
|
||||
int loopcount;
|
||||
float time;
|
||||
};
|
||||
|
||||
// volume reader
|
||||
float volume;
|
||||
|
Reference in New Issue
Block a user