3D Audio GSoC:
authorJoerg Mueller <nexyon@gmail.com>
Tue, 21 Jun 2011 20:39:41 +0000 (20:39 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Tue, 21 Jun 2011 20:39:41 +0000 (20:39 +0000)
- Sequencer dynamics: Now it's possible to change the output channels and the resampling quality also increased (previously maximum quality was 44,1 kHz)
- Changed two buffers to use ffmpeg allocation, not sure if that helps somehow.

21 files changed:
intern/audaspace/intern/AUD_C-API.cpp
intern/audaspace/intern/AUD_C-API.h
intern/audaspace/intern/AUD_ChannelMapperReader.cpp
intern/audaspace/intern/AUD_ChannelMapperReader.h
intern/audaspace/intern/AUD_Mixer.cpp
intern/audaspace/intern/AUD_Mixer.h
intern/audaspace/intern/AUD_SequencerFactory.cpp
intern/audaspace/intern/AUD_SequencerFactory.h
intern/audaspace/intern/AUD_SequencerReader.cpp
intern/audaspace/intern/AUD_SequencerReader.h
release/scripts/presets/ffmpeg/DV.py
release/scripts/presets/ffmpeg/DVD.py
release/scripts/presets/ffmpeg/SVCD.py
release/scripts/presets/ffmpeg/VCD.py
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/sound.c
source/blender/blenkernel/intern/writeffmpeg.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_scene.c

index b52243c..db76b9b 100644 (file)
@@ -882,16 +882,11 @@ AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds)
 
 AUD_Sound* AUD_createSequencer(int muted, void* data, AUD_volumeFunction volume)
 {
-/* AUD_XXX should be this: but AUD_createSequencer is called before the device
- * is initialized.
-
-       return new AUD_SequencerFactory(AUD_device->getSpecs().specs, data, volume);
-*/
+       // specs are changed at a later point!
        AUD_Specs specs;
        specs.channels = AUD_CHANNELS_STEREO;
        specs.rate = AUD_RATE_44100;
        AUD_Reference<AUD_SequencerFactory>* sequencer = new AUD_Reference<AUD_SequencerFactory>(new AUD_SequencerFactory(specs, muted, data, volume));
-       (*sequencer)->setThis(sequencer);
        return reinterpret_cast<AUD_Sound*>(sequencer);
 }
 
@@ -928,6 +923,16 @@ void AUD_muteSequencer(AUD_Sound* sequencer, AUD_Reference<AUD_SequencerEntry>*
        ((AUD_SequencerFactory*)sequencer->get())->mute(*entry, mute);
 }
 
+void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer)
+{
+       ((AUD_SequencerFactory*)sequencer->get())->setSpecs(AUD_device->getSpecs().specs);
+}
+
+void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs)
+{
+       ((AUD_SequencerFactory*)sequencer->get())->setSpecs(specs);
+}
+
 int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length)
 {
        AUD_DeviceSpecs specs;
index b818140..72d423e 100644 (file)
@@ -469,6 +469,10 @@ extern void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SEntry* entry,
 extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SEntry* entry,
                                                  char mute);
 
+extern void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer);
+
+extern void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs);
+
 extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length);
 
 extern void AUD_startPlayback(void);
index ab7b531..4ac1982 100644 (file)
@@ -44,6 +44,12 @@ AUD_ChannelMapperReader::~AUD_ChannelMapperReader()
        delete[] m_mapping;
 }
 
+void AUD_ChannelMapperReader::setChannels(AUD_Channels channels)
+{
+       m_target_channels = channels;
+       calculateMapping();
+}
+
 float AUD_ChannelMapperReader::angleDistance(float alpha, float beta)
 {
        alpha = fabs(alpha - beta);
index 949bb44..3da34ed 100644 (file)
@@ -109,6 +109,8 @@ public:
         */
        ~AUD_ChannelMapperReader();
 
+       void setChannels(AUD_Channels channels);
+
        virtual AUD_Specs getSpecs() const;
        virtual void read(int& length, bool& eos, sample_t* buffer);
 };
index e669981..cfdf2b0 100644 (file)
@@ -73,6 +73,11 @@ AUD_DeviceSpecs AUD_Mixer::getSpecs() const
        return m_specs;
 }
 
+void AUD_Mixer::setSpecs(AUD_Specs specs)
+{
+       m_specs.specs = specs;
+}
+
 void AUD_Mixer::clear(int length)
 {
        m_buffer.assureSize(length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs));
index a68d86d..5ca801b 100644 (file)
@@ -47,7 +47,7 @@ protected:
        /**
         * The output specification.
         */
-       const AUD_DeviceSpecs m_specs;
+       AUD_DeviceSpecs m_specs;
 
        /**
         * The length of the mixing buffer.
@@ -81,6 +81,12 @@ public:
         */
        AUD_DeviceSpecs getSpecs() const;
 
+       /**
+        * Sets the target specification for superposing.
+        * \param specs The target specification.
+        */
+       void setSpecs(AUD_Specs specs);
+
        /**
         * Mixes a buffer.
         * \param buffer The buffer to superpose.
index 1787dea..6907d76 100644 (file)
@@ -48,9 +48,12 @@ AUD_SequencerFactory::~AUD_SequencerFactory()
 {
 }
 
-void AUD_SequencerFactory::setThis(AUD_Reference<AUD_SequencerFactory>* self)
+void AUD_SequencerFactory::setSpecs(AUD_Specs specs)
 {
-       m_this = self;
+       m_specs = specs;
+
+       for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++)
+               (*i)->setSpecs(m_specs);
 }
 
 void AUD_SequencerFactory::mute(bool muted)
@@ -103,7 +106,7 @@ void AUD_SequencerFactory::mute(AUD_Reference<AUD_SequencerEntry> entry, bool mu
 
 AUD_Reference<AUD_IReader> AUD_SequencerFactory::createReader()
 {
-       AUD_Reference<AUD_SequencerReader> reader = new AUD_SequencerReader(*m_this, m_entries,
+       AUD_Reference<AUD_SequencerReader> reader = new AUD_SequencerReader(this, m_entries,
                                                                                                                  m_specs, m_data,
                                                                                                                  m_volume);
        m_readers.push_front(reader);
index 37a332b..4e57a22 100644 (file)
@@ -66,7 +66,6 @@ private:
        bool m_muted;
        void* m_data;
        AUD_volumeFunction m_volume;
-       AUD_Reference<AUD_SequencerFactory>* m_this;
 
        // hide copy constructor and operator=
        AUD_SequencerFactory(const AUD_SequencerFactory&);
@@ -76,7 +75,7 @@ public:
        AUD_SequencerFactory(AUD_Specs specs, bool muted, void* data, AUD_volumeFunction volume);
        ~AUD_SequencerFactory();
 
-       void setThis(AUD_Reference<AUD_SequencerFactory>* self);
+       void setSpecs(AUD_Specs specs);
 
        void mute(bool muted);
        bool getMute() const;
index 9ee0b39..a930931 100644 (file)
@@ -95,6 +95,22 @@ void AUD_SequencerReader::remove(AUD_Reference<AUD_SequencerEntry> entry)
        }
 }
 
+void AUD_SequencerReader::setSpecs(AUD_Specs specs)
+{
+       m_mixer->setSpecs(specs);
+
+       AUD_Reference<AUD_SequencerStrip> strip;
+       for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
+       {
+               strip = *i;
+               if(!strip->mapper.isNull())
+               {
+                       strip->mapper->setChannels(specs.channels);
+                       strip->resampler->setRate(specs.rate);
+               }
+       }
+}
+
 bool AUD_SequencerReader::isSeekable() const
 {
        return true;
@@ -149,24 +165,30 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
                                                        strip->reader = (*strip->old_sound)->createReader();
                                                        // resample
                                                        #ifdef WITH_SAMPLERATE
-                                                               strip->reader = new AUD_SRCResampleReader(strip->reader, m_mixer->getSpecs().specs);
+                                                               strip->resampler = new AUD_SRCResampleReader(strip->reader, m_mixer->getSpecs().specs);
                                                        #else
-                                                               strip->reader = new AUD_LinearResampleReader(strip->reader, m_mixer->getSpecs().specs);
+                                                               strip->resampler = new AUD_LinearResampleReader(strip->reader, m_mixer->getSpecs().specs);
                                                        #endif
 
                                                        // rechannel
-                                                       strip->reader = new AUD_ChannelMapperReader(strip->reader, m_mixer->getSpecs().channels);
+                                                       strip->mapper = new AUD_ChannelMapperReader(AUD_Reference<AUD_IReader>(strip->resampler), m_mixer->getSpecs().channels);
                                                }
                                                catch(AUD_Exception)
                                                {
                                                        strip->reader = NULL;
+                                                       strip->resampler = NULL;
+                                                       strip->mapper = NULL;
                                                }
                                        }
                                        else
+                                       {
                                                strip->reader = NULL;
+                                               strip->resampler = NULL;
+                                               strip->mapper = NULL;
+                                       }
                                }
 
-                               if(!strip->reader.isNull())
+                               if(!strip->mapper.isNull())
                                {
                                        end = floor(strip->entry->end * rate);
                                        if(m_position < end)
@@ -185,9 +207,9 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
                                                        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, eos, m_buffer.getBuffer());
+                                                       if(strip->mapper->getPosition() != current)
+                                                               strip->mapper->seek(current);
+                                                       strip->mapper->read(len, eos, m_buffer.getBuffer());
                                                        m_mixer->mix(m_buffer.getBuffer(), skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate));
                                                }
                                        }
index e769b34..625bad3 100644 (file)
 #include "AUD_IReader.h"
 #include "AUD_SequencerFactory.h"
 #include "AUD_Buffer.h"
-class AUD_Mixer;
+#include "AUD_Mixer.h"
+#include "AUD_ResampleReader.h"
+#include "AUD_ChannelMapperReader.h"
 
 struct AUD_SequencerStrip
 {
        AUD_Reference<AUD_IReader> reader;
+       AUD_Reference<AUD_ResampleReader> resampler;
+       AUD_Reference<AUD_ChannelMapperReader> mapper;
        AUD_Reference<AUD_SequencerEntry> entry;
        AUD_Reference<AUD_IFactory>* old_sound;
 };
@@ -94,6 +98,7 @@ public:
 
        void add(AUD_Reference<AUD_SequencerEntry> entry);
        void remove(AUD_Reference<AUD_SequencerEntry> entry);
+       void setSpecs(AUD_Specs specs);
 
        virtual bool isSeekable() const;
        virtual void seek(int position);
index 46d2a0a..926fb24 100644 (file)
@@ -11,3 +11,4 @@ else:
 
 bpy.context.scene.render.ffmpeg_audio_mixrate = 48000
 bpy.context.scene.render.ffmpeg_audio_codec = "PCM"
+bpy.context.scene.render.ffmpeg_audio_channels = 2
index e18ec9f..196b5d6 100644 (file)
@@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 10080000
 bpy.context.scene.render.ffmpeg_audio_codec = "AC3"
 bpy.context.scene.render.ffmpeg_audio_bitrate = 448
 bpy.context.scene.render.ffmpeg_audio_mixrate = 48000
+bpy.context.scene.render.ffmpeg_audio_channels = 6
index c71a385..e4459ab 100644 (file)
@@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 0
 bpy.context.scene.render.ffmpeg_audio_bitrate = 224
 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100
 bpy.context.scene.render.ffmpeg_audio_codec = "MP2"
+bpy.context.scene.render.ffmpeg_audio_channels = 2
index faf27ef..c2b73e6 100644 (file)
@@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 2352 * 75 * 8
 bpy.context.scene.render.ffmpeg_audio_bitrate = 224
 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100
 bpy.context.scene.render.ffmpeg_audio_codec = "MP2"
+bpy.context.scene.render.ffmpeg_audio_channels = 2
index 54ca18e..9ff4470 100644 (file)
@@ -596,7 +596,9 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel):
         col.prop(rd, "ffmpeg_audio_bitrate")
         col.prop(rd, "ffmpeg_audio_mixrate")
 
-        split.prop(rd, "ffmpeg_audio_volume", slider=True)
+        col = split.column()
+        col.prop(rd, "ffmpeg_audio_volume", slider=True)
+        col.prop(rd, "ffmpeg_audio_channels")
 
 
 class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel):
index 51eaba3..e045bd0 100644 (file)
@@ -469,6 +469,7 @@ Scene *add_scene(const char *name)
        sce->r.ffcodecdata.audio_mixrate = 44100;
        sce->r.ffcodecdata.audio_volume = 1.0f;
        sce->r.ffcodecdata.audio_bitrate = 192;
+       sce->r.ffcodecdata.audio_channels = 2;
 
        BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine));
 
index 60a24c2..9b86b87 100644 (file)
@@ -346,6 +346,7 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start,
 
        AUD_setDeviceVolume(mixdown, volume);
 
+       AUD_setSequencerSpecs(scene->sound_scene, specs.specs);
        AUD_freeHandle(AUD_playDevice(mixdown, scene->sound_scene, start / FPS));
 
        return mixdown;
@@ -405,6 +406,9 @@ static void sound_start_play_scene(struct Scene *scene)
 {
        if(scene->sound_scene_handle)
                AUD_stop(scene->sound_scene_handle);
+
+       AUD_setSequencerDeviceSpecs(scene->sound_scene);
+
        if((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1)))
                AUD_setLoop(scene->sound_scene_handle, -1);
 }
index c729565..26de31b 100644 (file)
@@ -549,7 +549,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
        c->sample_rate = rd->ffcodecdata.audio_mixrate;
        c->bit_rate = ffmpeg_audio_bitrate*1000;
        c->sample_fmt = SAMPLE_FMT_S16;
-       c->channels = 2;
+       c->channels = rd->ffcodecdata.audio_channels;
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec) {
                //XXX error("Couldn't find a valid audio codec");
@@ -574,12 +574,11 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
                        audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
        }
 
-       audio_output_buffer = (uint8_t*)MEM_mallocN(
-               audio_outbuf_size, "FFMPEG audio encoder input buffer");
+       audio_output_buffer = (uint8_t*)av_malloc(
+               audio_outbuf_size);
 
-       audio_input_buffer = (uint8_t*)MEM_mallocN(
-               audio_input_samples * c->channels * sizeof(int16_t),
-               "FFMPEG audio encoder output buffer");
+       audio_input_buffer = (uint8_t*)av_malloc(
+               audio_input_samples * c->channels * sizeof(int16_t));
 
        audio_time = 0.0f;
 
@@ -701,7 +700,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        
        if (ffmpeg_type == FFMPEG_DV) {
                fmt->audio_codec = CODEC_ID_PCM_S16LE;
-               if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000) {
+               if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
                        BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
                        return 0;
                }
@@ -971,11 +970,11 @@ void end_ffmpeg(void)
                video_buffer = 0;
        }
        if (audio_output_buffer) {
-               MEM_freeN(audio_output_buffer);
+               av_free(audio_output_buffer);
                audio_output_buffer = 0;
        }
        if (audio_input_buffer) {
-               MEM_freeN(audio_input_buffer);
+               av_free(audio_input_buffer);
                audio_input_buffer = 0;
        }
 
index b8a7261..50be7b8 100644 (file)
@@ -11474,6 +11474,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                        kb->slidermax = kb->slidermin + 1.0f;
                        }
                }
+
+               {
+                       Scene *scene;
+                       for (scene=main->scene.first; scene; scene=scene->id.next)
+                               scene->r.ffcodecdata.audio_channels = 2;
+               }
        }
        
        if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) {
index 100a66d..2fc92aa 100644 (file)
@@ -126,6 +126,8 @@ typedef struct FFMpegCodecData {
        int video_bitrate;
        int audio_bitrate;
        int audio_mixrate;
+       int audio_channels;
+       int audio_pad;
        float audio_volume;
        int gop_size;
        int flags;
index 1322a18..a8d8d87 100644 (file)
@@ -98,6 +98,14 @@ EnumPropertyItem snap_element_items[] = {
        {SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"},
        {0, NULL, 0, NULL, NULL}};
 
+static EnumPropertyItem audio_channel_items[] = {
+       {1, "MONO", 0, "Mono", "Set audio channels to mono"},
+       {2, "STEREO", 0, "Stereo", "Set audio channels to stereo"},
+       {4, "SURROUND4", 0, "4 Channels", "Set audio channels to 4 channels"},
+       {6, "SURROUND51", 0, "5.1 Surround", "Set audio channels to 5.1 surround sound"},
+       {8, "SURROUND71", 0, "7.1 Surround", "Set audio channels to 7.1 surround sound"},
+       {0, NULL, 0, NULL, NULL}};
+
 EnumPropertyItem image_type_items[] = {
        {0, "", 0, "Image", NULL},
        {R_BMP, "BMP", ICON_FILE_IMAGE, "BMP", "Output image in bitmap format"},
@@ -2468,6 +2476,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Volume", "Audio volume");
        RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
 
+       prop= RNA_def_property(srna, "ffmpeg_audio_channels", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "ffcodecdata.audio_channels");
+       RNA_def_property_enum_items(prop, audio_channel_items);
+       RNA_def_property_ui_text(prop, "Audio Channels", "Sets the audio channel count");
 #endif
 
        prop= RNA_def_property(srna, "fps", PROP_INT, PROP_NONE);