From ef3acaedc1eb530b263e9235d83d853f8282a278 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sat, 28 Apr 2012 13:16:29 +0000 Subject: Audio: * Fix for [#31099] Audio in Meta-Strips Plays Beyond Strip Cut * Adding a split files option to the mixdown operator which then renders each channel into a separate file --- intern/audaspace/intern/AUD_C-API.cpp | 42 ++++++++++++++++++++++++++++ intern/audaspace/intern/AUD_C-API.h | 15 ++++++++++ intern/audaspace/intern/AUD_FileWriter.cpp | 36 ++++++++++++++++++++++++ intern/audaspace/intern/AUD_FileWriter.h | 10 +++++++ source/blender/blenkernel/intern/sequencer.c | 26 +++++++++++++---- source/blender/editors/sound/sound_ops.c | 11 ++++++-- 6 files changed, 132 insertions(+), 8 deletions(-) diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 9100a277124..50b47650696 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "AUD_NULLDevice.h" #include "AUD_I3DDevice.h" @@ -1236,6 +1237,47 @@ const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int lengt } } +const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate) +{ + try + { + AUD_SequencerFactory* f = dynamic_cast(sound->get()); + + f->setSpecs(specs.specs); + + std::vector > writers; + + int channels = specs.channels; + specs.channels = AUD_CHANNELS_MONO; + + for(int i = 0; i < channels; i++) + { + std::stringstream stream; + std::string fn = filename; + size_t index = fn.find_last_of('.'); + size_t index_slash = fn.find_last_of('/'); + size_t index_backslash = fn.find_last_of('\\'); + if((index == std::string::npos) || + ((index < index_slash) && (index_slash != std::string::npos)) || + ((index < index_backslash) && (index_backslash != std::string::npos))) + stream << filename << "_" << (i + 1); + else + stream << fn.substr(0, index) << "_" << (i + 1) << fn.substr(index); + writers.push_back(AUD_FileWriter::createWriter(stream.str(), specs, format, codec, bitrate)); + } + + AUD_Reference reader = f->createQualityReader(); + reader->seek(start); + AUD_FileWriter::writeReader(reader, writers, length, buffersize); + + return NULL; + } + catch(AUD_Exception& e) + { + return e.str; + } +} + AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start) { try diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index 8388af2170d..a52a1fa8369 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -709,6 +709,21 @@ extern void* AUD_getSet(void* set); */ extern const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate); +/** + * Mixes a sound down into multiple files. + * \param sound The sound scene to mix down. + * \param start The start frame. + * \param length The count of frames to write. + * \param buffersize How many samples should be written at once. + * \param filename The file to write to, the channel number and an underscore are added at the beginning. + * \param specs The file's audio specification. + * \param format The file's container format. + * \param codec The codec used for encoding the audio data. + * \param bitrate The bitrate for encoding. + * \return An error message or NULL in case of success. + */ +extern const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate); + /** * Opens a read device and prepares it for mixdown of the sound scene. * \param specs Output audio specifications. diff --git a/intern/audaspace/intern/AUD_FileWriter.cpp b/intern/audaspace/intern/AUD_FileWriter.cpp index df76b667e3f..f74021acad1 100644 --- a/intern/audaspace/intern/AUD_FileWriter.cpp +++ b/intern/audaspace/intern/AUD_FileWriter.cpp @@ -93,3 +93,39 @@ void AUD_FileWriter::writeReader(AUD_Reference reader, AUD_Referenc writer->write(len, buf); } } + +void AUD_FileWriter::writeReader(AUD_Reference reader, std::vector >& writers, unsigned int length, unsigned int buffersize) +{ + AUD_Buffer buffer(buffersize * AUD_SAMPLE_SIZE(reader->getSpecs())); + AUD_Buffer buffer2(buffersize * sizeof(sample_t)); + sample_t* buf = buffer.getBuffer(); + sample_t* buf2 = buffer2.getBuffer(); + + int len; + bool eos = false; + int channels = reader->getSpecs().channels; + + for(unsigned int pos = 0; ((pos < length) || (length <= 0)) && !eos; pos += len) + { + len = buffersize; + if((len > length - pos) && (length > 0)) + len = length - pos; + reader->read(len, eos, buf); + + for(int channel = 0; channel < channels; channel++) + { + for(int i = 0; i < len; i++) + { + // clamping! + if(buf[i * channels + channel] > 1) + buf2[i] = 1; + else if(buf[i * channels + channel] < -1) + buf2[i] = -1; + else + buf2[i] = buf[i * channels + channel]; + } + + writers[channel]->write(len, buf2); + } + } +} diff --git a/intern/audaspace/intern/AUD_FileWriter.h b/intern/audaspace/intern/AUD_FileWriter.h index c9ee2b1ee12..385aba5ef45 100644 --- a/intern/audaspace/intern/AUD_FileWriter.h +++ b/intern/audaspace/intern/AUD_FileWriter.h @@ -31,6 +31,7 @@ #define __AUD_FILEWRITER_H__ #include +#include #include "AUD_Reference.h" @@ -68,6 +69,15 @@ public: * \param buffersize How many samples should be transfered at once. */ static void writeReader(AUD_Reference reader, AUD_Reference writer, unsigned int length, unsigned int buffersize); + + /** + * Writes a reader to several writers. + * \param reader The reader to read from. + * \param writers The writers to write to. + * \param length How many samples should be transfered. + * \param buffersize How many samples should be transfered at once. + */ + static void writeReader(AUD_Reference reader, std::vector >& writers, unsigned int length, unsigned int buffersize); }; #endif //__AUD_FILEWRITER_H__ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 1c06f1da018..470e1a1c529 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -515,8 +515,17 @@ void build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int *totseq, *seqar = tseqar; } +static int metaseq_start(Sequence *metaseq) +{ + return metaseq->start + metaseq->startofs; +} -static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) +static int metaseq_end(Sequence *metaseq) +{ + return metaseq->start + metaseq->len - metaseq->endofs; +} + +static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metaseq, int start, int end) { Sequence *seq; @@ -524,23 +533,28 @@ static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) * since sound is played outside of evaluating the imbufs, */ for (seq = metaseq->seqbase.first; seq; seq = seq->next) { if (seq->type == SEQ_META) { - seq_update_sound_bounds_recursive(scene, seq); + seq_update_sound_bounds_recursive_rec(scene, seq, MAX2(start, metaseq_start(seq)), MIN2(end, metaseq_end(seq))); } else if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { if (seq->scene_sound) { int startofs = seq->startofs; int endofs = seq->endofs; - if (seq->startofs + seq->start < metaseq->start + metaseq->startofs) - startofs = metaseq->start + metaseq->startofs - seq->start; + if (seq->startofs + seq->start < start) + startofs = start - seq->start; - if (seq->start + seq->len - seq->endofs > metaseq->start + metaseq->len - metaseq->endofs) - endofs = seq->start + seq->len - metaseq->start - metaseq->len + metaseq->endofs; + if (seq->start + seq->len - seq->endofs > end) + endofs = seq->start + seq->len - end; sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, seq->start + seq->len - endofs, startofs); } } } } +static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) +{ + seq_update_sound_bounds_recursive_rec(scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq)); +} + void calc_sequence_disp(Scene *scene, Sequence *seq) { if (seq->startofs && seq->startstill) seq->startstill = 0; diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index c238789446f..49eb85d62b4 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -318,6 +318,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) char filename[FILE_MAX]; Scene *scene; Main *bmain; + int split; int bitrate, accuracy; AUD_DeviceSpecs specs; @@ -333,6 +334,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) specs.format = RNA_enum_get(op->ptr, "format"); container = RNA_enum_get(op->ptr, "container"); codec = RNA_enum_get(op->ptr, "codec"); + split = RNA_boolean_get(op->ptr, "split_channels"); scene = CTX_data_scene(C); bmain = CTX_data_main(C); specs.channels = scene->r.ffcodecdata.audio_channels; @@ -341,8 +343,12 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) BLI_strncpy(filename, path, sizeof(filename)); BLI_path_abs(filename, bmain->name); - result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS, - accuracy, filename, specs, container, codec, bitrate); + if(split) + result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS, + accuracy, filename, specs, container, codec, bitrate); + else + result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS, + accuracy, filename, specs, container, codec, bitrate); if (result) { BKE_report(op->reports, RPT_ERROR, result); @@ -590,6 +596,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) RNA_def_enum(ot->srna, "codec", codec_items, AUD_CODEC_FLAC, "Codec", "Audio Codec"); RNA_def_enum(ot->srna, "format", format_items, AUD_FORMAT_S16, "Format", "Sample format"); RNA_def_int(ot->srna, "bitrate", 192, 32, 512, "Bitrate", "Bitrate in kbit/s", 32, 512); + RNA_def_boolean(ot->srna, "split_channels", 0, "Split channels", "Each channel will be rendered into a mono file."); #endif // WITH_AUDASPACE } -- cgit v1.2.3