VSE: Sound equalizer modifier

The sound equalizer is using the Audaspace FFT Convolver.
The blender part creates an array of descriptions of power per "band"
and orders the creation of Equalizer (ISound) in the Audaspace.

Modifier can be created on sound strips. It lets you define
amplification or attenuation over frequency range from 30Hz to 20 kHz.
The power is limited to -30 db - 30 db. This is done using curve
mapping widget.

Co-authored-by: menda <alguien@aqui.es>
Co-authored-by: Richard Antalik <richardantalik@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/105613
This commit is contained in:
Marcos Perez 2023-08-30 22:36:36 +02:00 committed by Richard Antalik
parent 9600b74318
commit 1015bed2fd
22 changed files with 722 additions and 93 deletions

@ -37,7 +37,18 @@ find_path(FFTW3_INCLUDE_DIR
include
)
find_library(FFTW3_LIBRARY
set(_FFTW3_LIBRARIES)
find_library(FFTW3_LIBRARY_F
NAMES
fftw3f
HINTS
${_fftw3_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
find_library(FFTW3_LIBRARY_D
NAMES
fftw3
HINTS
@ -46,17 +57,22 @@ find_library(FFTW3_LIBRARY
lib64 lib
)
list(APPEND _FFTW3_LIBRARIES "${FFTW3_LIBRARY_F}")
list(APPEND _FFTW3_LIBRARIES "${FFTW3_LIBRARY_D}")
# handle the QUIETLY and REQUIRED arguments and set FFTW3_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fftw3 DEFAULT_MSG
FFTW3_LIBRARY FFTW3_INCLUDE_DIR)
_FFTW3_LIBRARIES FFTW3_INCLUDE_DIR)
if(FFTW3_FOUND)
set(FFTW3_LIBRARIES ${FFTW3_LIBRARY})
set(FFTW3_LIBRARIES ${_FFTW3_LIBRARIES})
set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR})
endif()
unset(_FFTW3_LIBRARIES)
mark_as_advanced(
FFTW3_INCLUDE_DIR
FFTW3_LIBRARY

@ -7,7 +7,12 @@ set(SHARED_LIBRARY FALSE) # "Build Shared Library"
set(WITH_C TRUE) # "Build C Module"
set(WITH_DOCS FALSE) # "Build C++ HTML Documentation with Doxygen"
set(WITH_FFMPEG ${WITH_CODEC_FFMPEG}) # "Build With FFMPEG"
set(WITH_FFTW FALSE) # "Build With FFTW"
if(DEFINED WITH_FFTW3) # "Build With FFTW"
set(FFTW_FOUND TRUE)
set(WITH_FFTW ${WITH_FFTW3})
set(FFTW_INCLUDE_DIR ${FFTW3_INCLUDE_DIRS})
set(FFTW_LIBRARY ${FFTW3_LIBRARIES})
endif()
set(WITH_LIBSNDFILE ${WITH_CODEC_SNDFILE}) # "Build With LibSndFile"
set(SEPARATE_C FALSE) # "Build C Binding as separate library"
set(PLUGIN_COREAUDIO FALSE) # "Build CoreAudio Plugin"

@ -962,7 +962,11 @@ class SEQUENCER_MT_strip(Menu):
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
else:
layout.separator()
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if strip_type in {
@ -1103,17 +1107,19 @@ class SEQUENCER_MT_context_menu(Menu):
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
col = layout.column()
col.menu("SEQUENCER_MT_add_transitions", text="Add Transition")
elif selected_sequences_count >= 2:
else:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")
if selected_sequences_count >= 1:
col = layout.column()
@ -2503,8 +2509,13 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
strip = context.active_sequence_strip
ed = context.scene.sequence_editor
if strip.type == 'SOUND':
sound = strip.sound
else:
sound = None
layout.prop(strip, "use_linear_modifiers")
if sound is None:
layout.prop(strip, "use_linear_modifiers")
layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
layout.operator("sequencer.strip_modifier_copy")
@ -2531,45 +2542,66 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
row.operator("sequencer.strip_modifier_remove", text="", icon='X', emboss=False).name = mod.name
if mod.show_expanded:
row = box.row()
row.prop(mod, "input_mask_type", expand=True)
if mod.input_mask_type == 'STRIP':
sequences_object = ed
if ed.meta_stack:
sequences_object = ed.meta_stack[-1]
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
if sound is None:
row = box.row()
row.prop(mod, "mask_time", expand=True)
row.prop(mod, "input_mask_type", expand=True)
if mod.type == 'COLOR_BALANCE':
box.prop(mod, "color_multiply")
draw_color_balance(box, mod.color_balance)
elif mod.type == 'CURVES':
box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
elif mod.type == 'HUE_CORRECT':
box.template_curve_mapping(mod, "curve_mapping", type='HUE')
elif mod.type == 'BRIGHT_CONTRAST':
col = box.column()
col.prop(mod, "bright")
col.prop(mod, "contrast")
elif mod.type == 'WHITE_BALANCE':
col = box.column()
col.prop(mod, "white_value")
elif mod.type == 'TONEMAP':
col = box.column()
col.prop(mod, "tonemap_type")
if mod.tonemap_type == 'RD_PHOTORECEPTOR':
col.prop(mod, "intensity")
if mod.input_mask_type == 'STRIP':
sequences_object = ed
if ed.meta_stack:
sequences_object = ed.meta_stack[-1]
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
row = box.row()
row.prop(mod, "mask_time", expand=True)
if mod.type == 'COLOR_BALANCE':
box.prop(mod, "color_multiply")
draw_color_balance(box, mod.color_balance)
elif mod.type == 'CURVES':
box.template_curve_mapping(mod, "curve_mapping", type='COLOR', show_tone=True)
elif mod.type == 'HUE_CORRECT':
box.template_curve_mapping(mod, "curve_mapping", type='HUE')
elif mod.type == 'BRIGHT_CONTRAST':
col = box.column()
col.prop(mod, "bright")
col.prop(mod, "contrast")
col.prop(mod, "adaptation")
col.prop(mod, "correction")
elif mod.tonemap_type == 'RH_SIMPLE':
col.prop(mod, "key")
col.prop(mod, "offset")
col.prop(mod, "gamma")
elif mod.type == 'WHITE_BALANCE':
col = box.column()
col.prop(mod, "white_value")
elif mod.type == 'TONEMAP':
col = box.column()
col.prop(mod, "tonemap_type")
if mod.tonemap_type == 'RD_PHOTORECEPTOR':
col.prop(mod, "intensity")
col.prop(mod, "contrast")
col.prop(mod, "adaptation")
col.prop(mod, "correction")
elif mod.tonemap_type == 'RH_SIMPLE':
col.prop(mod, "key")
col.prop(mod, "offset")
col.prop(mod, "gamma")
else:
if mod.type == 'SOUND_EQUALIZER':
eq_row = box.row()
# eq_graphs = eq_row.operator_menu_enum("sequencer.strip_modifier_equalizer_redefine", "graphs")
# eq_graphs.name = mod.name
flow = box.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
for i in range(len(mod.graphics)):
soundEq = mod.graphics[i]
col = flow.column()
box = col.box()
split = box.split(factor=0.4)
split.label(text = "{:.2f}".format(soundEq.curve_mapping.clip_min_x))
split.label(text = "Hz")
split.alignment = "RIGHT"
split.label(text = "{:.2f}".format(soundEq.curve_mapping.clip_max_x))
box.template_curve_mapping(soundEq, "curve_mapping",
type='NONE', levels=False, brush=True, use_negative_slope=True, show_tone=False)
second_row = col.row()
second_row.label(text = "dB")
second_row.alignment = "CENTER"
class SEQUENCER_PT_annotation(AnnotationDataPanel, SequencerButtonsPanel_Output, Panel):

@ -24,8 +24,13 @@ struct ImBuf;
struct Scopes;
struct rctf;
void BKE_curvemapping_set_defaults(
struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy);
void BKE_curvemapping_set_defaults(struct CurveMapping *cumap,
int tot,
float minx,
float miny,
float maxx,
float maxy,
short default_handle_type);
struct CurveMapping *BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
void BKE_curvemapping_free_data(struct CurveMapping *cumap);
void BKE_curvemapping_free(struct CurveMapping *cumap);

@ -127,6 +127,7 @@ void BKE_sound_update_scene_listener(struct Scene *scene);
void *BKE_sound_scene_add_scene_sound(
struct Scene *scene, struct Sequence *sequence, int startframe, int endframe, int frameskip);
void *BKE_sound_scene_add_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
void *BKE_sound_add_scene_sound(
@ -145,8 +146,14 @@ void BKE_sound_move_scene_sound(const struct Scene *scene,
double audio_offset);
void BKE_sound_move_scene_sound_defaults(struct Scene *scene, struct Sequence *sequence);
/* Join the Sequence with the structure in Audaspace, the second parameter is a bSound */
void BKE_sound_update_scene_sound(void *handle, struct bSound *sound);
/* Join the Sequence with the structure in Audaspace, the second parameter is the AUD_Sound created
* in Audaspace previously
*/
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle);
void BKE_sound_set_cfra(int cfra);
void BKE_sound_set_scene_volume(struct Scene *scene, float volume);

@ -776,7 +776,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK);
@ -813,7 +813,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE);
@ -850,7 +850,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER);
@ -886,12 +886,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
/* Curve. */
custom_curve = brush->gpencil_settings->curve_sensitivity;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY);
custom_curve = brush->gpencil_settings->curve_strength;
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH);

@ -34,8 +34,13 @@
/* ***************** operations on full struct ************* */
void BKE_curvemapping_set_defaults(
CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
void BKE_curvemapping_set_defaults(CurveMapping *cumap,
int tot,
float minx,
float miny,
float maxx,
float maxy,
short default_handle_type)
{
int a;
float clipminx, clipminy, clipmaxx, clipmaxy;
@ -57,14 +62,23 @@ void BKE_curvemapping_set_defaults(
cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
for (a = 0; a < tot; a++) {
if (default_handle_type == HD_VECT) {
cumap->cm[a].default_handle_type = CUMA_HANDLE_VECTOR;
}
else if (default_handle_type == HD_AUTO_ANIM) {
cumap->cm[a].default_handle_type = CUMA_HANDLE_AUTO_ANIM;
}
cumap->cm[a].totpoint = 2;
cumap->cm[a].curve = static_cast<CurveMapPoint *>(
MEM_callocN(2 * sizeof(CurveMapPoint), "curve points"));
cumap->cm[a].curve[0].x = minx;
cumap->cm[a].curve[0].y = miny;
cumap->cm[a].curve[0].flag |= default_handle_type;
cumap->cm[a].curve[1].x = maxx;
cumap->cm[a].curve[1].y = maxy;
cumap->cm[a].curve[1].flag |= default_handle_type;
}
cumap->changed_timestamp = 0;
@ -76,7 +90,7 @@ CurveMapping *BKE_curvemapping_add(int tot, float minx, float miny, float maxx,
cumap = static_cast<CurveMapping *>(MEM_callocN(sizeof(CurveMapping), "new curvemap"));
BKE_curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
BKE_curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy, HD_AUTO);
return cumap;
}
@ -238,6 +252,7 @@ CurveMapPoint *BKE_curvemap_insert(CurveMap *cuma, float x, float y)
cmp[a].x = x;
cmp[a].y = y;
cmp[a].flag = CUMA_SELECT;
cmp[a].flag |= cuma->default_handle_type;
foundloc = true;
newcmp = &cmp[a];
}
@ -266,6 +281,7 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
switch (preset) {
case CURVE_PRESET_LINE:
case CURVE_PRESET_CONSTANT_MEDIAN:
cuma->totpoint = 2;
break;
case CURVE_PRESET_SHARP:
@ -297,6 +313,10 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
cuma->curve = static_cast<CurveMapPoint *>(
MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points"));
for (int i = 0; i < cuma->totpoint; i++) {
cuma->curve[i].flag = cuma->default_handle_type;
}
switch (preset) {
case CURVE_PRESET_LINE:
cuma->curve[0].x = clipr->xmin;
@ -304,10 +324,18 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = clipr->ymin;
if (slope == CURVEMAP_SLOPE_POS_NEG) {
cuma->curve[0].flag &= ~CUMA_HANDLE_AUTO_ANIM;
cuma->curve[1].flag &= ~CUMA_HANDLE_AUTO_ANIM;
cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
}
break;
case CURVE_PRESET_CONSTANT_MEDIAN:
cuma->curve[0].x = clipr->xmin;
cuma->curve[0].y = (clipr->ymin + clipr->ymax) / 2.0f;
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = (clipr->ymin + clipr->ymax) / 2.0f;
break;
case CURVE_PRESET_SHARP:
cuma->curve[0].x = 0;
cuma->curve[0].y = 1;

@ -158,7 +158,7 @@ static void scene_init_data(ID *id)
STRNCPY(scene->r.bake.filepath, U.renderdir);
mblur_shutter_curve = &scene->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(mblur_shutter_curve);
BKE_curvemap_reset(mblur_shutter_curve->cm,
&mblur_shutter_curve->clipr,

@ -789,6 +789,11 @@ void BKE_sound_update_scene_sound(void *handle, bSound *sound)
AUD_SequenceEntry_setSound(handle, sound->playback_handle);
}
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
{
AUD_SequenceEntry_setSound(handle, sound_handle);
}
void BKE_sound_set_cfra(int cfra)
{
sound_cfra = cfra;

@ -999,7 +999,7 @@ void blo_do_versions_270(FileData *fd, Library * /*lib*/, Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
CurveMapping *curve_mapping = &scene->r.mblur_shutter_curve;
BKE_curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
BKE_curvemapping_init(curve_mapping);
BKE_curvemap_reset(
curve_mapping->cm, &curve_mapping->clipr, CURVE_PRESET_MAX, CURVEMAP_SLOPE_POS_NEG);

@ -279,6 +279,7 @@ void SEQUENCER_OT_strip_modifier_add(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_remove(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_move(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_copy(struct wmOperatorType *ot);
void SEQUENCER_OT_strip_modifier_equalizer_redefine(struct wmOperatorType *ot);
/* `sequencer_view.cc` */

@ -11,6 +11,8 @@
#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
#include "BKE_context.h"
#include "WM_api.hh"
@ -24,28 +26,13 @@
#include "SEQ_relations.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
/* Own include. */
#include "sequencer_intern.h"
/*********************** Add modifier operator *************************/
static bool strip_modifier_active_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
if (ed) {
Sequence *seq = SEQ_select_active_get(scene);
if (seq) {
return SEQ_sequence_supports_modifiers(seq);
}
}
return false;
}
static int strip_modifier_add_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@ -60,6 +47,21 @@ static int strip_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static const EnumPropertyItem *filter_modifiers_by_sequence_type(bContext *C,
PointerRNA * /* ptr */,
PropertyRNA * /* prop */,
bool * /* r_free */)
{
Scene *scene = CTX_data_scene(C);
Sequence *seq = SEQ_select_active_get(scene);
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM)) {
return rna_enum_sequence_sound_modifier_type_items;
}
else {
return rna_enum_sequence_video_modifier_type_items;
}
}
void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -71,18 +73,17 @@ void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = strip_modifier_add_exec;
ot->poll = strip_modifier_active_poll;
/*
* No poll because a modifier can be applied to any kind of strip
*/
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_enum(ot->srna,
"type",
rna_enum_sequence_modifier_type_items,
seqModifierType_ColorBalance,
"Type",
"");
prop = RNA_def_enum(ot->srna, "type", rna_enum_dummy_NULL_items, 0, "Type", "");
RNA_def_enum_funcs(prop, filter_modifiers_by_sequence_type);
ot->prop = prop;
}
@ -105,7 +106,12 @@ static int strip_modifier_remove_exec(bContext *C, wmOperator *op)
BLI_remlink(&seq->modifiers, smd);
SEQ_modifier_free(smd);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM)) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
}
else {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -122,7 +128,9 @@ void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = strip_modifier_remove_exec;
ot->poll = strip_modifier_active_poll;
/*
* No poll is needed because all kind of strips can have their modifiers erased
*/
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -168,7 +176,13 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op)
}
}
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM)) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
}
else {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -191,7 +205,10 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
/* api callbacks */
ot->exec = strip_modifier_move_exec;
ot->poll = strip_modifier_active_poll;
/*
* No poll is needed because all strips can have modifiers
*/
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -221,11 +238,19 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
int isSound = ELEM(seq->type, SEQ_TYPE_SOUND_RAM);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
if (seq_iter->flag & SELECT) {
if (seq_iter == seq) {
continue;
}
int seq_iter_is_sound = ELEM(seq_iter->type, SEQ_TYPE_SOUND_RAM);
/* If original is sound, only copy to "sound" strips
* If original is not sound, only copy to "not sound" strips
*/
if (isSound != seq_iter_is_sound)
continue;
if (type == SEQ_MODIFIER_COPY_REPLACE) {
if (seq_iter->modifiers.first) {
@ -245,7 +270,13 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op)
}
}
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM)) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
}
else {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -271,7 +302,9 @@ void SEQUENCER_OT_strip_modifier_copy(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = strip_modifier_copy_exec;
ot->poll = strip_modifier_active_poll;
/*
* No poll is needed because all kind of strips can have modifier
*/
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -279,3 +312,60 @@ void SEQUENCER_OT_strip_modifier_copy(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", type_items, SEQ_MODIFIER_COPY_REPLACE, "Type", "");
}
static int strip_modifier_equalizer_redefine_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Sequence *seq = SEQ_select_active_get(scene);
SequenceModifierData *smd;
char name[MAX_NAME];
RNA_string_get(op->ptr, "name", name);
int number = RNA_enum_get(op->ptr, "graphs");
smd = SEQ_modifier_find_by_name(seq, name);
if (!smd) {
return OPERATOR_CANCELLED;
}
SEQ_sound_equalizermodifier_set_graphs((SoundEqualizerModifierData *)smd, number);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_strip_modifier_equalizer_redefine(wmOperatorType *ot)
{
static const EnumPropertyItem enum_modifier_equalizer_presets_items[] = {
{1, "SIMPLE", 0, "Unique", "One unique graphical definition"},
{2, "DOUBLE", 0, "Double", "Graphical definition in 2 sections"},
{3, "TRIPLE", 0, "Triplet", "Graphical definition in 3 sections"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
/* identifiers */
ot->name = "Redefine equalizer graphs";
ot->idname = "SEQUENCER_OT_strip_modifier_equalizer_redefine";
ot->description = "Redefine equalizer graphs";
/* api callbacks */
ot->exec = strip_modifier_equalizer_redefine_exec;
/*
* No poll because a modifier can be applied to any kind of strip
*/
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_enum(
ot->srna, "graphs", enum_modifier_equalizer_presets_items, 1, "Graphs", "Number of graphs");
ot->prop = prop;
prop = RNA_def_string(
ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to redefine");
RNA_def_property_flag(prop, PROP_HIDDEN);
}

@ -104,6 +104,7 @@ void sequencer_operatortypes()
WM_operatortype_append(SEQUENCER_OT_strip_modifier_remove);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_move);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_copy);
WM_operatortype_append(SEQUENCER_OT_strip_modifier_equalizer_redefine);
/* sequencer_view.h */
WM_operatortype_append(SEQUENCER_OT_sample);

@ -60,6 +60,8 @@ typedef struct CurveMap {
/** For RGB curves, pre-multiplied extrapolation vector. */
float premul_ext_in[2];
float premul_ext_out[2];
short default_handle_type;
char _pad[6];
} CurveMap;
typedef struct CurveMapping {
@ -107,6 +109,7 @@ typedef enum eCurveMappingPreset {
CURVE_PRESET_ROOT = 6,
CURVE_PRESET_GAUSS = 7,
CURVE_PRESET_BELL = 8,
CURVE_PRESET_CONSTANT_MEDIAN = 9,
} eCurveMappingPreset;
/** #CurveMapping.tone */

@ -527,6 +527,21 @@ enum {
/** \} */
/** \name Sound Modifiers
* \{ */
typedef struct EQCurveMappingData {
struct EQCurveMappingData *next, *prev;
struct CurveMapping curve_mapping;
} EQCurveMappingData;
typedef struct SoundEqualizerModifierData {
SequenceModifierData modifier;
/* EQCurveMappingData */
ListBase graphics;
} SoundEqualizerModifierData;
/** \} */
/* -------------------------------------------------------------------- */
/** \name Scopes
* \{ */
@ -760,6 +775,7 @@ enum {
seqModifierType_Mask = 5,
seqModifierType_WhiteBalance = 6,
seqModifierType_Tonemap = 7,
seqModifierType_SoundEqualizer = 8,
/* Keep last. */
NUM_SEQUENCE_MODIFIER_TYPES,
};

@ -45,6 +45,8 @@ DEF_ENUM(rna_enum_object_modifier_type_items)
DEF_ENUM(rna_enum_constraint_type_items)
DEF_ENUM(rna_enum_boidrule_type_items)
DEF_ENUM(rna_enum_sequence_modifier_type_items)
DEF_ENUM(rna_enum_sequence_video_modifier_type_items)
DEF_ENUM(rna_enum_sequence_sound_modifier_type_items)
DEF_ENUM(rna_enum_object_greasepencil_modifier_type_items)
DEF_ENUM(rna_enum_object_shaderfx_type_items)

@ -72,7 +72,24 @@ const EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
{seqModifierType_Mask, "MASK", ICON_NONE, "Mask", ""},
{seqModifierType_Tonemap, "TONEMAP", ICON_NONE, "Tone Map", ""},
{seqModifierType_WhiteBalance, "WHITE_BALANCE", ICON_NONE, "White Balance", ""},
{0, nullptr, 0, nullptr, nullptr},
{seqModifierType_SoundEqualizer, "SOUND_EQUALIZER", ICON_NONE, "Sound Equalizer", ""},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_sequence_video_modifier_type_items[] = {
{seqModifierType_BrightContrast, "BRIGHT_CONTRAST", ICON_NONE, "Bright/Contrast", ""},
{seqModifierType_ColorBalance, "COLOR_BALANCE", ICON_NONE, "Color Balance", ""},
{seqModifierType_Curves, "CURVES", ICON_NONE, "Curves", ""},
{seqModifierType_HueCorrect, "HUE_CORRECT", ICON_NONE, "Hue Correct", ""},
{seqModifierType_Mask, "MASK", ICON_NONE, "Mask", ""},
{seqModifierType_Tonemap, "TONEMAP", ICON_NONE, "Tone Map", ""},
{seqModifierType_WhiteBalance, "WHITE_BALANCE", ICON_NONE, "White Balance", ""},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_sequence_sound_modifier_type_items[] = {
{seqModifierType_SoundEqualizer, "SOUND_EQUALIZER", ICON_NONE, "Equalizer", ""},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_strip_color_items[] = {
@ -1286,6 +1303,8 @@ static StructRNA *rna_SequenceModifier_refine(PointerRNA *ptr)
return &RNA_WhiteBalanceModifier;
case seqModifierType_Tonemap:
return &RNA_SequencerTonemapModifierData;
case seqModifierType_SoundEqualizer:
return &RNA_SoundEqualizerModifier;
default:
return &RNA_SequenceModifier;
}
@ -1344,14 +1363,34 @@ static void rna_SequenceModifier_name_set(PointerRNA *ptr, const char *value)
}
}
static void rna_SequenceModifier_update(Main * /*bmain*/, Scene * /*scene*/, PointerRNA *ptr)
static void rna_SequenceModifier_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
{
/* strip from other scenes could be modified, so using active scene is not reliable */
Scene *scene = (Scene *)ptr->owner_id;
Editing *ed = SEQ_editing_get(scene);
Sequence *seq = sequence_get_by_modifier(ed, static_cast<SequenceModifierData *>(ptr->data));
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
DEG_relations_tag_update(bmain);
}
else {
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
}
/*
* Update of Curve in an EQ Sound Modifier
*/
static void rna_SequenceModifier_EQCurveMapping_update(Main *bmain,
Scene * /*scene*/,
PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
static bool rna_SequenceModifier_otherSequence_poll(PointerRNA *ptr, PointerRNA value)
@ -1554,6 +1593,23 @@ static char *rna_SeqTimelineChannel_path(const PointerRNA *ptr)
}
}
static EQCurveMappingData *rna_Sequence_SoundEqualizer_Curve_add(SoundEqualizerModifierData *semd,
bContext * /* C */,
float min_freq,
float max_freq)
{
EQCurveMappingData *eqcmd = SEQ_sound_equalizermodifier_add_graph(semd, min_freq, max_freq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
return eqcmd;
}
static void rna_Sequence_SoundEqualizer_Curve_clear(SoundEqualizerModifierData *semd,
bContext * /* C */)
{
SEQ_sound_equalizermodifier_free((SequenceModifierData *)semd);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
#else
static void rna_def_strip_element(BlenderRNA *brna)
@ -3757,6 +3813,89 @@ static void rna_def_modifiers(BlenderRNA *brna)
rna_def_tonemap_modifier(brna);
}
static void rna_def_graphical_sound_equalizer(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
/* Define Sound EQ */
srna = RNA_def_struct(brna, "EQCurveMappingData", NULL);
RNA_def_struct_sdna(srna, "EQCurveMappingData");
RNA_def_struct_ui_text(srna, "EQCurveMappingData", "EQCurveMappingData");
prop = RNA_def_property(srna, "curve_mapping", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curve_mapping");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve Mapping", "");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_EQCurveMapping_update");
}
static void rna_def_sound_equalizer_modifier(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
srna = RNA_def_struct(brna, "SoundEqualizerModifier", "SequenceModifier");
RNA_def_struct_sdna(srna, "SoundEqualizerModifierData");
RNA_def_struct_ui_text(srna, "SoundEqualizerModifier", "Equalize audio");
/* Sound Equalizers*/
prop = RNA_def_property(srna, "graphics", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "EQCurveMappingData");
RNA_def_property_ui_text(
prop, "Graphical definition equalization", "Graphical definition equalization");
/* add band*/
func = RNA_def_function(srna, "new_graphic", "rna_Sequence_SoundEqualizer_Curve_add");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Add a new EQ band");
parm = RNA_def_float(func,
"min_freq",
SOUND_EQUALIZER_DEFAULT_MIN_FREQ,
0.0,
SOUND_EQUALIZER_DEFAULT_MAX_FREQ, /* Hard min and max */
"Minimum Frequency",
"Minimum Frequency",
0.0,
SOUND_EQUALIZER_DEFAULT_MAX_FREQ); /* Soft min and max */
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_float(func,
"max_freq",
SOUND_EQUALIZER_DEFAULT_MAX_FREQ,
0.0,
SOUND_EQUALIZER_DEFAULT_MAX_FREQ, /* Hard min and max */
"Maximum Frequency",
"Maximum Frequency",
0.0,
SOUND_EQUALIZER_DEFAULT_MAX_FREQ); /* Soft min and max */
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
/* return type */
parm = RNA_def_pointer(func,
"graphic_eqs",
"EQCurveMappingData",
"",
"Newly created graphical Equalizer definition");
RNA_def_function_return(func, parm);
/* clear all modifiers */
func = RNA_def_function(srna, "clear_soundeqs", "rna_Sequence_SoundEqualizer_Curve_clear");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func,
"Remove all graphical equalizers from the Equalizer modifier");
rna_def_graphical_sound_equalizer(brna);
}
static void rna_def_sound_modifiers(BlenderRNA *brna)
{
rna_def_sound_equalizer_modifier(brna);
}
void RNA_def_sequencer(BlenderRNA *brna)
{
rna_def_color_balance(brna);
@ -3782,6 +3921,7 @@ void RNA_def_sequencer(BlenderRNA *brna)
rna_def_effect(brna);
rna_def_effects(brna);
rna_def_modifiers(brna);
rna_def_sound_modifiers(brna);
}
#endif

@ -101,6 +101,10 @@ if(WITH_AUDASPACE)
)
endif()
add_definitions(-DWITH_AUDASPACE)
if(WITH_FFTW3)
add_definitions(-DWITH_CONVOLUTION)
endif()
endif()
blender_add_lib(bf_sequencer "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

@ -16,12 +16,51 @@ struct Main;
struct Scene;
struct Sequence;
struct bSound;
struct SequencerSoundEqualizer;
struct BlendWriter;
struct BlendDataReader;
struct ListBase;
struct SoundEqualizerModifierData;
#define SOUND_EQUALIZER_DEFAULT_MIN_FREQ 30.0
#define SOUND_EQUALIZER_DEFAULT_MAX_FREQ 20000.0
#define SOUND_EQUALIZER_DEFAULT_MAX_DB 35.0
#define SOUND_EQUALIZER_SIZE_CONVERSION 2048
#define SOUND_EQUALIZER_SIZE_DEFINITION 1000
void SEQ_sound_update_bounds_all(struct Scene *scene);
void SEQ_sound_update_bounds(struct Scene *scene, struct Sequence *seq);
void SEQ_sound_update(struct Scene *scene, struct bSound *sound);
void SEQ_sound_update_length(struct Main *bmain, struct Scene *scene);
float SEQ_sound_pitch_get(const struct Scene *scene, const struct Sequence *seq);
struct EQCurveMappingData *SEQ_sound_equalizer_add(struct SoundEqualizerModifierData *semd,
float minX,
float maxX);
void SEQ_sound_blend_write(struct BlendWriter *writer, struct ListBase *soundbase);
void SEQ_sound_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb);
void *SEQ_sound_modifier_recreator(struct Sequence *seq,
struct SequenceModifierData *smd,
void *sound);
void SEQ_sound_equalizermodifier_init_data(struct SequenceModifierData *smd);
void SEQ_sound_equalizermodifier_free(struct SequenceModifierData *smd);
void SEQ_sound_equalizermodifier_copy_data(struct SequenceModifierData *target,
struct SequenceModifierData *smd);
void *SEQ_sound_equalizermodifier_recreator(struct Sequence *seq,
struct SequenceModifierData *smd,
void *sound);
void SEQ_sound_equalizermodifier_set_graphs(struct SoundEqualizerModifierData *semd, int number);
const struct SoundModifierWorkerInfo *SEQ_sound_modifier_worker_info_get(int type);
struct EQCurveMappingData *SEQ_sound_equalizermodifier_add_graph(
struct SoundEqualizerModifierData *semd, float min_freq, float max_freq);
void SEQ_sound_equalizermodifier_remove_graph(struct SoundEqualizerModifierData *semd,
struct EQCurveMappingData *gsed);
typedef struct SoundModifierWorkerInfo {
int type;
void *(*recreator)(struct Sequence *seq, struct SequenceModifierData *smd, void *sound);
} SoundModifierWorkerInfo;
#ifdef __cplusplus
}

@ -30,6 +30,7 @@
#include "SEQ_modifier.h"
#include "SEQ_render.h"
#include "SEQ_sound.h"
#include "BLO_read_write.hh"
@ -741,7 +742,7 @@ static void curves_init_data(SequenceModifierData *smd)
{
CurvesModifierData *cmd = (CurvesModifierData *)smd;
BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
}
static void curves_free_data(SequenceModifierData *smd)
@ -860,7 +861,7 @@ static void hue_correct_init_data(SequenceModifierData *smd)
HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
int c;
BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
for (c = 0; c < 3; c++) {
@ -1371,6 +1372,15 @@ static SequenceModifierTypeInfo seqModifier_Tonemap = {
/*apply*/ tonemapmodifier_apply,
};
static SequenceModifierTypeInfo seqModifier_SoundEqualizer = {
CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Equalizer"), /* name */
"SoundEqualizerModifierData", /* struct_name */
sizeof(SoundEqualizerModifierData), /* struct_size */
SEQ_sound_equalizermodifier_init_data, /* init_data */
SEQ_sound_equalizermodifier_free, /* free_data */
SEQ_sound_equalizermodifier_copy_data, /* copy_data */
NULL, /* apply */
};
/** \} */
/* -------------------------------------------------------------------- */
@ -1388,6 +1398,7 @@ static void sequence_modifier_type_info_init()
INIT_TYPE(Mask);
INIT_TYPE(WhiteBalance);
INIT_TYPE(Tonemap);
INIT_TYPE(SoundEqualizer);
#undef INIT_TYPE
}
@ -1591,6 +1602,13 @@ void SEQ_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
BKE_curvemapping_blend_write(writer, &hcmd->curve_mapping);
}
else if (smd->type == seqModifierType_SoundEqualizer) {
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
BLO_write_struct_by_name(writer, "EQCurveMappingData", eqcmd);
BKE_curvemapping_blend_write(writer, &eqcmd->curve_mapping);
}
}
}
else {
BLO_write_struct(writer, SequenceModifierData, smd);
@ -1617,6 +1635,13 @@ void SEQ_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
BKE_curvemapping_blend_read(reader, &hcmd->curve_mapping);
}
else if (smd->type == seqModifierType_SoundEqualizer) {
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
BLO_read_list(reader, &semd->graphics);
LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
BKE_curvemapping_blend_read(reader, &eqcmd->curve_mapping);
}
}
}
}

@ -918,6 +918,15 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
if (scene->id.recalc & ID_RECALC_AUDIO || seq->sound->id.recalc & ID_RECALC_AUDIO) {
BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
}
void *sound = seq->sound->playback_handle;
if (!BLI_listbase_is_empty(&seq->modifiers)) {
LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
sound = SEQ_sound_modifier_recreator(seq, smd, sound);
}
}
BKE_sound_update_sequence_handle(seq->scene_sound, sound);
}
BKE_sound_set_scene_sound_volume(
seq->scene_sound, seq->volume, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);

@ -9,7 +9,12 @@
*/
#include <cmath>
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
@ -17,10 +22,15 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLO_read_write.hh"
#include "BKE_colortools.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "AUD_Sound.h"
#include "SEQ_sound.h"
#include "SEQ_time.h"
@ -29,6 +39,9 @@
/* Unlike _update_sound_ functions,
* these ones take info from audaspace to update sequence length! */
const SoundModifierWorkerInfo workersSoundModifiers[] = {
{seqModifierType_SoundEqualizer, SEQ_sound_equalizermodifier_recreator}, {0, NULL}};
#ifdef WITH_AUDASPACE
static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, ListBase *seqbase)
{
@ -140,3 +153,191 @@ float SEQ_sound_pitch_get(const Scene *scene, const Sequence *seq)
}
return seq->speed_factor;
}
struct EQCurveMappingData *SEQ_sound_equalizer_add(SoundEqualizerModifierData *semd,
float minX,
float maxX)
{
EQCurveMappingData *eqcmd;
if (maxX < 0)
maxX = SOUND_EQUALIZER_DEFAULT_MAX_FREQ;
if (minX < 0)
minX = 0.0;
/* It's the same as BKE_curvemapping_add , but changing the name */
eqcmd = MEM_cnew<EQCurveMappingData>("Equalizer");
BKE_curvemapping_set_defaults(&eqcmd->curve_mapping,
1, /* tot*/
minX,
-SOUND_EQUALIZER_DEFAULT_MAX_DB, /* Min x, y */
maxX,
SOUND_EQUALIZER_DEFAULT_MAX_DB, /* Max x, y */
HD_AUTO_ANIM);
eqcmd->curve_mapping.preset = CURVE_PRESET_CONSTANT_MEDIAN;
rctf clipr;
clipr.xmin = minX;
clipr.xmax = maxX;
clipr.ymin = 0.0;
clipr.ymax = 0.0;
BKE_curvemap_reset(&eqcmd->curve_mapping.cm[0], &clipr, CURVE_PRESET_CONSTANT_MEDIAN, 0);
BLI_addtail(&semd->graphics, eqcmd);
return eqcmd;
}
void SEQ_sound_equalizermodifier_set_graphs(struct SoundEqualizerModifierData *semd, int number)
{
SEQ_sound_equalizermodifier_free((SequenceModifierData *)semd);
if (number == 1) {
SEQ_sound_equalizer_add(
semd, SOUND_EQUALIZER_DEFAULT_MIN_FREQ, SOUND_EQUALIZER_DEFAULT_MAX_FREQ);
}
else if (number == 2) {
SEQ_sound_equalizer_add(semd, 30.0, 2000.0);
SEQ_sound_equalizer_add(semd, 2000.1, 20000.0);
}
else if (number == 3) {
SEQ_sound_equalizer_add(semd, 30.0, 1000.0);
SEQ_sound_equalizer_add(semd, 1000.1, 5000.0);
SEQ_sound_equalizer_add(semd, 5000.1, 20000.0);
}
}
EQCurveMappingData *SEQ_sound_equalizermodifier_add_graph(struct SoundEqualizerModifierData *semd,
float min_freq,
float max_freq)
{
if (min_freq < 0.0)
return NULL;
if (max_freq < 0.0)
return NULL;
if (max_freq <= min_freq)
return NULL;
return SEQ_sound_equalizer_add(semd, min_freq, max_freq);
}
void SEQ_sound_equalizermodifier_remove_graph(struct SoundEqualizerModifierData *semd,
struct EQCurveMappingData *eqcmd)
{
BLI_remlink_safe(&semd->graphics, eqcmd);
MEM_freeN(eqcmd);
}
void SEQ_sound_equalizermodifier_init_data(SequenceModifierData *smd)
{
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
SEQ_sound_equalizer_add(
semd, SOUND_EQUALIZER_DEFAULT_MIN_FREQ, SOUND_EQUALIZER_DEFAULT_MAX_FREQ);
}
void SEQ_sound_equalizermodifier_free(SequenceModifierData *smd)
{
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
LISTBASE_FOREACH_MUTABLE (EQCurveMappingData *, eqcmd, &semd->graphics) {
BKE_curvemapping_free_data(&eqcmd->curve_mapping);
MEM_freeN(eqcmd);
}
BLI_listbase_clear(&semd->graphics);
}
void SEQ_sound_equalizermodifier_copy_data(struct SequenceModifierData *target,
struct SequenceModifierData *smd)
{
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
SoundEqualizerModifierData *semd_target = (SoundEqualizerModifierData *)target;
EQCurveMappingData *eqcmd_n;
BLI_listbase_clear(&semd_target->graphics);
LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
eqcmd_n = static_cast<EQCurveMappingData *>(MEM_dupallocN(eqcmd));
BKE_curvemapping_copy_data(&eqcmd_n->curve_mapping, &eqcmd->curve_mapping);
eqcmd_n->next = eqcmd_n->prev = NULL;
BLI_addtail(&semd_target->graphics, eqcmd_n);
}
}
void *SEQ_sound_equalizermodifier_recreator(struct Sequence *seq,
struct SequenceModifierData *smd,
void *sound)
{
UNUSED_VARS(seq);
SoundEqualizerModifierData *semd = (SoundEqualizerModifierData *)smd;
// No Equalizer definition
if (BLI_listbase_is_empty(&semd->graphics)) {
return sound;
}
float *buf = (float *)MEM_callocN(sizeof(float) * SOUND_EQUALIZER_SIZE_DEFINITION,
"eqrecreator");
CurveMapping *eq_mapping;
CurveMap *cm;
float minX;
float maxX;
float interval = SOUND_EQUALIZER_DEFAULT_MAX_FREQ / (float)SOUND_EQUALIZER_SIZE_DEFINITION;
// Visit all equalizer definitions
LISTBASE_FOREACH (EQCurveMappingData *, mapping, &semd->graphics) {
eq_mapping = &mapping->curve_mapping;
BKE_curvemapping_init(eq_mapping);
cm = eq_mapping->cm;
minX = eq_mapping->curr.xmin;
maxX = eq_mapping->curr.xmax;
int idx = (int)ceil(minX / interval);
int i = idx;
for (; i * interval <= maxX && i < SOUND_EQUALIZER_SIZE_DEFINITION; i++) {
float freq = i * interval;
float val = BKE_curvemap_evaluateF(eq_mapping, cm, freq);
if (fabs(val) > SOUND_EQUALIZER_DEFAULT_MAX_DB)
val = (val / fabs(val)) * SOUND_EQUALIZER_DEFAULT_MAX_DB;
buf[i] = val;
/* To soften lower limit, but not the first position which is the constant value */
if (i == idx && i > 2) {
buf[i - 1] = 0.5 * (buf[i] + buf[i - 1]);
}
}
/* To soften higher limit */
if (i < SOUND_EQUALIZER_SIZE_DEFINITION)
buf[i] = 0.5 * (buf[i] + buf[i - 1]);
}
AUD_Sound *equ = AUD_Sound_equalize(sound,
buf,
SOUND_EQUALIZER_SIZE_DEFINITION,
SOUND_EQUALIZER_DEFAULT_MAX_FREQ,
SOUND_EQUALIZER_SIZE_CONVERSION);
MEM_freeN(buf);
return equ;
}
const struct SoundModifierWorkerInfo *SEQ_sound_modifier_worker_info_get(int type)
{
for (int i = 0; workersSoundModifiers[i].type > 0; i++) {
if (workersSoundModifiers[i].type == type)
return &workersSoundModifiers[i];
}
return NULL;
}
void *SEQ_sound_modifier_recreator(struct Sequence *seq,
struct SequenceModifierData *smd,
void *sound)
{
if (!(smd->flag & SEQUENCE_MODIFIER_MUTE)) {
const SoundModifierWorkerInfo *smwi = SEQ_sound_modifier_worker_info_get(smd->type);
return smwi->recreator(seq, smd, sound);
}
return sound;
}