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
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "AUD_NULLDevice.h"
|
#include "AUD_NULLDevice.h"
|
||||||
#include "AUD_I3DDevice.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<AUD_SequencerFactory*>(sound->get());
|
||||||
|
|
||||||
|
f->setSpecs(specs.specs);
|
||||||
|
|
||||||
|
std::vector<AUD_Reference<AUD_IWriter> > 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<AUD_IReader> 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)
|
AUD_Device* AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound* sequencer, float volume, float start)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@@ -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);
|
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.
|
* Opens a read device and prepares it for mixdown of the sound scene.
|
||||||
* \param specs Output audio specifications.
|
* \param specs Output audio specifications.
|
||||||
|
@@ -93,3 +93,39 @@ void AUD_FileWriter::writeReader(AUD_Reference<AUD_IReader> reader, AUD_Referenc
|
|||||||
writer->write(len, buf);
|
writer->write(len, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AUD_FileWriter::writeReader(AUD_Reference<AUD_IReader> reader, std::vector<AUD_Reference<AUD_IWriter> >& 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#define __AUD_FILEWRITER_H__
|
#define __AUD_FILEWRITER_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "AUD_Reference.h"
|
#include "AUD_Reference.h"
|
||||||
|
|
||||||
@@ -68,6 +69,15 @@ public:
|
|||||||
* \param buffersize How many samples should be transfered at once.
|
* \param buffersize How many samples should be transfered at once.
|
||||||
*/
|
*/
|
||||||
static void writeReader(AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_IWriter> writer, unsigned int length, unsigned int buffersize);
|
static void writeReader(AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_IWriter> 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<AUD_IReader> reader, std::vector<AUD_Reference<AUD_IWriter> >& writers, unsigned int length, unsigned int buffersize);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__AUD_FILEWRITER_H__
|
#endif //__AUD_FILEWRITER_H__
|
||||||
|
@@ -515,8 +515,17 @@ void build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int *totseq,
|
|||||||
*seqar = tseqar;
|
*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;
|
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, */
|
* since sound is played outside of evaluating the imbufs, */
|
||||||
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
|
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
|
||||||
if (seq->type == SEQ_META) {
|
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)) {
|
else if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) {
|
||||||
if (seq->scene_sound) {
|
if (seq->scene_sound) {
|
||||||
int startofs = seq->startofs;
|
int startofs = seq->startofs;
|
||||||
int endofs = seq->endofs;
|
int endofs = seq->endofs;
|
||||||
if (seq->startofs + seq->start < metaseq->start + metaseq->startofs)
|
if (seq->startofs + seq->start < start)
|
||||||
startofs = metaseq->start + metaseq->startofs - seq->start;
|
startofs = start - seq->start;
|
||||||
|
|
||||||
if (seq->start + seq->len - seq->endofs > metaseq->start + metaseq->len - metaseq->endofs)
|
if (seq->start + seq->len - seq->endofs > end)
|
||||||
endofs = seq->start + seq->len - metaseq->start - metaseq->len + metaseq->endofs;
|
endofs = seq->start + seq->len - end;
|
||||||
sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, seq->start + seq->len - endofs, startofs);
|
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)
|
void calc_sequence_disp(Scene *scene, Sequence *seq)
|
||||||
{
|
{
|
||||||
if (seq->startofs && seq->startstill) seq->startstill = 0;
|
if (seq->startofs && seq->startstill) seq->startstill = 0;
|
||||||
|
@@ -318,6 +318,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
|
|||||||
char filename[FILE_MAX];
|
char filename[FILE_MAX];
|
||||||
Scene *scene;
|
Scene *scene;
|
||||||
Main *bmain;
|
Main *bmain;
|
||||||
|
int split;
|
||||||
|
|
||||||
int bitrate, accuracy;
|
int bitrate, accuracy;
|
||||||
AUD_DeviceSpecs specs;
|
AUD_DeviceSpecs specs;
|
||||||
@@ -333,6 +334,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
|
|||||||
specs.format = RNA_enum_get(op->ptr, "format");
|
specs.format = RNA_enum_get(op->ptr, "format");
|
||||||
container = RNA_enum_get(op->ptr, "container");
|
container = RNA_enum_get(op->ptr, "container");
|
||||||
codec = RNA_enum_get(op->ptr, "codec");
|
codec = RNA_enum_get(op->ptr, "codec");
|
||||||
|
split = RNA_boolean_get(op->ptr, "split_channels");
|
||||||
scene = CTX_data_scene(C);
|
scene = CTX_data_scene(C);
|
||||||
bmain = CTX_data_main(C);
|
bmain = CTX_data_main(C);
|
||||||
specs.channels = scene->r.ffcodecdata.audio_channels;
|
specs.channels = scene->r.ffcodecdata.audio_channels;
|
||||||
@@ -341,6 +343,10 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
|
|||||||
BLI_strncpy(filename, path, sizeof(filename));
|
BLI_strncpy(filename, path, sizeof(filename));
|
||||||
BLI_path_abs(filename, bmain->name);
|
BLI_path_abs(filename, bmain->name);
|
||||||
|
|
||||||
|
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,
|
result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
|
||||||
accuracy, filename, specs, container, codec, bitrate);
|
accuracy, filename, specs, container, codec, bitrate);
|
||||||
|
|
||||||
@@ -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, "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_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_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
|
#endif // WITH_AUDASPACE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user