1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup edsnd
22  */
23 
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_blenlib.h"
32 #include "BLI_utildefines.h"
33 
34 #include "DNA_packedFile_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_sequence_types.h"
37 #include "DNA_sound_types.h"
38 #include "DNA_space_types.h"
39 #include "DNA_userdef_types.h"
40 
41 #include "BKE_context.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_global.h"
44 #include "BKE_lib_id.h"
45 #include "BKE_main.h"
46 #include "BKE_packedFile.h"
47 #include "BKE_report.h"
48 #include "BKE_scene.h"
49 #include "BKE_sequencer.h"
50 #include "BKE_sound.h"
51 
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54 #include "RNA_enum_types.h"
55 
56 #include "UI_interface.h"
57 
58 #include "WM_api.h"
59 #include "WM_types.h"
60 
61 #ifdef WITH_AUDASPACE
62 #  include <AUD_Special.h>
63 #endif
64 
65 #include "DEG_depsgraph_query.h"
66 
67 #include "ED_sound.h"
68 #include "ED_util.h"
69 
70 /******************** open sound operator ********************/
71 
sound_open_cancel(bContext * UNUSED (C),wmOperator * op)72 static void sound_open_cancel(bContext *UNUSED(C), wmOperator *op)
73 {
74   MEM_freeN(op->customdata);
75   op->customdata = NULL;
76 }
77 
sound_open_init(bContext * C,wmOperator * op)78 static void sound_open_init(bContext *C, wmOperator *op)
79 {
80   PropertyPointerRNA *pprop;
81 
82   op->customdata = pprop = MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
83   UI_context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
84 }
85 
86 #ifdef WITH_AUDASPACE
sound_open_exec(bContext * C,wmOperator * op)87 static int sound_open_exec(bContext *C, wmOperator *op)
88 {
89   char path[FILE_MAX];
90   bSound *sound;
91   PropertyPointerRNA *pprop;
92   PointerRNA idptr;
93   Main *bmain = CTX_data_main(C);
94 
95   RNA_string_get(op->ptr, "filepath", path);
96   sound = BKE_sound_new_file(bmain, path);
97 
98   if (!op->customdata) {
99     sound_open_init(C, op);
100   }
101 
102   if (RNA_boolean_get(op->ptr, "mono")) {
103     sound->flags |= SOUND_FLAGS_MONO;
104   }
105 
106   if (RNA_boolean_get(op->ptr, "cache")) {
107     sound->flags |= SOUND_FLAGS_CACHING;
108   }
109 
110   /* hook into UI */
111   pprop = op->customdata;
112 
113   if (pprop->prop) {
114     /* when creating new ID blocks, use is already 1, but RNA
115      * pointer use also increases user, so this compensates it */
116     id_us_min(&sound->id);
117 
118     RNA_id_pointer_create(&sound->id, &idptr);
119     RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL);
120     RNA_property_update(C, &pprop->ptr, pprop->prop);
121   }
122 
123   DEG_relations_tag_update(bmain);
124 
125   MEM_freeN(op->customdata);
126   return OPERATOR_FINISHED;
127 }
128 
129 #else /* WITH_AUDASPACE */
130 
sound_open_exec(bContext * UNUSED (C),wmOperator * op)131 static int sound_open_exec(bContext *UNUSED(C), wmOperator *op)
132 {
133   BKE_report(op->reports, RPT_ERROR, "Compiled without sound support");
134 
135   return OPERATOR_CANCELLED;
136 }
137 
138 #endif
139 
sound_open_invoke(bContext * C,wmOperator * op,const wmEvent * event)140 static int sound_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
141 {
142   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
143     return sound_open_exec(C, op);
144   }
145 
146   sound_open_init(C, op);
147 
148   return WM_operator_filesel(C, op, event);
149 }
150 
SOUND_OT_open(wmOperatorType * ot)151 static void SOUND_OT_open(wmOperatorType *ot)
152 {
153   /* identifiers */
154   ot->name = "Open Sound";
155   ot->description = "Load a sound file";
156   ot->idname = "SOUND_OT_open";
157 
158   /* api callbacks */
159   ot->exec = sound_open_exec;
160   ot->invoke = sound_open_invoke;
161   ot->cancel = sound_open_cancel;
162 
163   /* flags */
164   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
165 
166   /* properties */
167   WM_operator_properties_filesel(ot,
168                                  FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE,
169                                  FILE_SPECIAL,
170                                  FILE_OPENFILE,
171                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
172                                  FILE_DEFAULTDISPLAY,
173                                  FILE_SORT_ALPHA);
174   RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
175   RNA_def_boolean(ot->srna, "mono", false, "Mono", "Merge all the sound's channels into one");
176 }
177 
SOUND_OT_open_mono(wmOperatorType * ot)178 static void SOUND_OT_open_mono(wmOperatorType *ot)
179 {
180   /* identifiers */
181   ot->name = "Open Sound Mono";
182   ot->description = "Load a sound file as mono";
183   ot->idname = "SOUND_OT_open_mono";
184 
185   /* api callbacks */
186   ot->exec = sound_open_exec;
187   ot->invoke = sound_open_invoke;
188   ot->cancel = sound_open_cancel;
189 
190   /* flags */
191   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
192 
193   /* properties */
194   WM_operator_properties_filesel(ot,
195                                  FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE,
196                                  FILE_SPECIAL,
197                                  FILE_OPENFILE,
198                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
199                                  FILE_DEFAULTDISPLAY,
200                                  FILE_SORT_ALPHA);
201   RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
202   RNA_def_boolean(ot->srna, "mono", true, "Mono", "Mixdown the sound to mono");
203 }
204 
205 /* ******************************************************* */
206 
207 static void sound_update_animation_flags(Scene *scene);
208 
sound_update_animation_flags_fn(Sequence * seq,void * user_data)209 static int sound_update_animation_flags_fn(Sequence *seq, void *user_data)
210 {
211   struct FCurve *fcu;
212   Scene *scene = (Scene *)user_data;
213   bool driven;
214 
215   fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
216   if (fcu || driven) {
217     seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
218   }
219   else {
220     seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
221   }
222 
223   fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
224   if (fcu || driven) {
225     seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
226   }
227   else {
228     seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
229   }
230 
231   fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
232   if (fcu || driven) {
233     seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
234   }
235   else {
236     seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
237   }
238 
239   if (seq->type == SEQ_TYPE_SCENE) {
240     /* TODO(sergey): For now we do manual recursion into the scene strips,
241      * but perhaps it should be covered by recursive_apply?
242      */
243     sound_update_animation_flags(seq->scene);
244   }
245 
246   return 0;
247 }
248 
sound_update_animation_flags(Scene * scene)249 static void sound_update_animation_flags(Scene *scene)
250 {
251   struct FCurve *fcu;
252   bool driven;
253   Sequence *seq;
254 
255   if (scene->id.tag & LIB_TAG_DOIT) {
256     return;
257   }
258   scene->id.tag |= LIB_TAG_DOIT;
259 
260   SEQ_ALL_BEGIN (scene->ed, seq) {
261     BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_fn, scene);
262   }
263   SEQ_ALL_END;
264 
265   fcu = id_data_find_fcurve(&scene->id, scene, &RNA_Scene, "audio_volume", 0, &driven);
266   if (fcu || driven) {
267     scene->audio.flag |= AUDIO_VOLUME_ANIMATED;
268   }
269   else {
270     scene->audio.flag &= ~AUDIO_VOLUME_ANIMATED;
271   }
272 }
273 
sound_update_animation_flags_exec(bContext * C,wmOperator * UNUSED (op))274 static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
275 {
276   Scene *scene = CTX_data_scene(C);
277 
278   BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
279   sound_update_animation_flags(CTX_data_scene(C));
280   DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
281   return OPERATOR_FINISHED;
282 }
283 
SOUND_OT_update_animation_flags(wmOperatorType * ot)284 static void SOUND_OT_update_animation_flags(wmOperatorType *ot)
285 {
286   /*
287    * This operator is needed to set a correct state of the sound animation
288    * System. Unfortunately there's no really correct place to call the exec
289    * function, that's why I made it an operator that's only visible in the
290    * search menu. Apart from that the bake animation operator calls it too.
291    */
292 
293   /* identifiers */
294   ot->name = "Update Animation";
295   ot->description = "Update animation flags";
296   ot->idname = "SOUND_OT_update_animation_flags";
297 
298   /* api callbacks */
299   ot->exec = sound_update_animation_flags_exec;
300 
301   /* flags */
302   ot->flag = OPTYPE_REGISTER;
303 }
304 
305 /* ******************************************************* */
306 
sound_bake_animation_exec(bContext * C,wmOperator * UNUSED (op))307 static int sound_bake_animation_exec(bContext *C, wmOperator *UNUSED(op))
308 {
309   Scene *scene = CTX_data_scene(C);
310   /* NOTE: We will be forcefully evaluating dependency graph at every frame, so no need to ensure
311    * current scene state is evaluated as it will be lost anyway. */
312   struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
313   int oldfra = scene->r.cfra;
314   int cfra;
315 
316   sound_update_animation_flags_exec(C, NULL);
317 
318   for (cfra = (scene->r.sfra > 0) ? (scene->r.sfra - 1) : 0; cfra <= scene->r.efra + 1; cfra++) {
319     scene->r.cfra = cfra;
320     BKE_scene_graph_update_for_newframe(depsgraph);
321   }
322 
323   scene->r.cfra = oldfra;
324   BKE_scene_graph_update_for_newframe(depsgraph);
325 
326   return OPERATOR_FINISHED;
327 }
328 
SOUND_OT_bake_animation(wmOperatorType * ot)329 static void SOUND_OT_bake_animation(wmOperatorType *ot)
330 {
331   /* identifiers */
332   ot->name = "Update Animation Cache";
333   ot->description = "Update the audio animation cache";
334   ot->idname = "SOUND_OT_bake_animation";
335 
336   /* api callbacks */
337   ot->exec = sound_bake_animation_exec;
338 
339   /* flags */
340   ot->flag = OPTYPE_REGISTER;
341 }
342 
343 /******************** mixdown operator ********************/
344 
sound_mixdown_exec(bContext * C,wmOperator * op)345 static int sound_mixdown_exec(bContext *C, wmOperator *op)
346 {
347 #ifdef WITH_AUDASPACE
348   char path[FILE_MAX];
349   char filename[FILE_MAX];
350   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
351   Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
352   Main *bmain = CTX_data_main(C);
353   int split;
354 
355   int bitrate, accuracy;
356   AUD_DeviceSpecs specs;
357   AUD_Container container;
358   AUD_Codec codec;
359   const char *result;
360 
361   sound_bake_animation_exec(C, op);
362 
363   RNA_string_get(op->ptr, "filepath", path);
364   bitrate = RNA_int_get(op->ptr, "bitrate") * 1000;
365   accuracy = RNA_int_get(op->ptr, "accuracy");
366   specs.format = RNA_enum_get(op->ptr, "format");
367   container = RNA_enum_get(op->ptr, "container");
368   codec = RNA_enum_get(op->ptr, "codec");
369   split = RNA_boolean_get(op->ptr, "split_channels");
370   specs.channels = scene_eval->r.ffcodecdata.audio_channels;
371   specs.rate = scene_eval->r.ffcodecdata.audio_mixrate;
372 
373   BLI_strncpy(filename, path, sizeof(filename));
374   BLI_path_abs(filename, BKE_main_blendfile_path(bmain));
375 
376   const double fps = (((double)scene_eval->r.frs_sec) / (double)scene_eval->r.frs_sec_base);
377   const int start_frame = scene_eval->r.sfra;
378   const int end_frame = scene_eval->r.efra;
379 
380   if (split) {
381     result = AUD_mixdown_per_channel(scene_eval->sound_scene,
382                                      start_frame * specs.rate / fps,
383                                      (end_frame - start_frame + 1) * specs.rate / fps,
384                                      accuracy,
385                                      filename,
386                                      specs,
387                                      container,
388                                      codec,
389                                      bitrate,
390                                      NULL,
391                                      NULL);
392   }
393   else {
394     result = AUD_mixdown(scene_eval->sound_scene,
395                          start_frame * specs.rate / fps,
396                          (end_frame - start_frame + 1) * specs.rate / fps,
397                          accuracy,
398                          filename,
399                          specs,
400                          container,
401                          codec,
402                          bitrate,
403                          NULL,
404                          NULL);
405   }
406 
407   BKE_sound_reset_scene_specs(scene_eval);
408 
409   if (result) {
410     BKE_report(op->reports, RPT_ERROR, result);
411     return OPERATOR_CANCELLED;
412   }
413 #else  /* WITH_AUDASPACE */
414   (void)C;
415   (void)op;
416 #endif /* WITH_AUDASPACE */
417   return OPERATOR_FINISHED;
418 }
419 
420 #ifdef WITH_AUDASPACE
421 static const EnumPropertyItem container_items[] = {
422 #  ifdef WITH_FFMPEG
423     {AUD_CONTAINER_AC3, "AC3", 0, "ac3", "Dolby Digital ATRAC 3"},
424 #  endif
425     {AUD_CONTAINER_FLAC, "FLAC", 0, "flac", "Free Lossless Audio Codec"},
426 #  ifdef WITH_FFMPEG
427     {AUD_CONTAINER_MATROSKA, "MATROSKA", 0, "mkv", "Matroska"},
428     {AUD_CONTAINER_MP2, "MP2", 0, "mp2", "MPEG-1 Audio Layer II"},
429     {AUD_CONTAINER_MP3, "MP3", 0, "mp3", "MPEG-2 Audio Layer III"},
430 #  endif
431     {AUD_CONTAINER_OGG, "OGG", 0, "ogg", "Xiph.Org Ogg Container"},
432     {AUD_CONTAINER_WAV, "WAV", 0, "wav", "Waveform Audio File Format"},
433     {0, NULL, 0, NULL, NULL},
434 };
435 
436 static const char *snd_ext_sound[] = {
437     ".ac3",
438     ".flac",
439     ".mkv",
440     ".mp2",
441     ".mp3",
442     ".ogg",
443     ".wav",
444     NULL,
445 };
446 
sound_mixdown_check(bContext * UNUSED (C),wmOperator * op)447 static bool sound_mixdown_check(bContext *UNUSED(C), wmOperator *op)
448 {
449   AUD_Container container = RNA_enum_get(op->ptr, "container");
450 
451   const char *extension = NULL;
452 
453   const EnumPropertyItem *item = container_items;
454   while (item->identifier != NULL) {
455     if (item->value == container) {
456       const char **ext = snd_ext_sound;
457       while (*ext != NULL) {
458         if (STREQ(*ext + 1, item->name)) {
459           extension = *ext;
460           break;
461         }
462 
463         ext++;
464       }
465     }
466     item++;
467   }
468 
469   if (extension) {
470     PropertyRNA *prop;
471     char filepath[FILE_MAX];
472 
473     int check;
474 
475     prop = RNA_struct_find_property(op->ptr, "filepath");
476     RNA_property_string_get(op->ptr, prop, filepath);
477 
478     if (BLI_path_extension_check_array(filepath, snd_ext_sound)) {
479       check = BLI_path_extension_replace(filepath, FILE_MAX, extension);
480     }
481     else {
482       check = BLI_path_extension_ensure(filepath, FILE_MAX, extension);
483     }
484 
485     if (!check) {
486       return check;
487     }
488 
489     RNA_property_string_set(op->ptr, prop, filepath);
490     return true;
491   }
492 
493   return false;
494 }
495 
496 #endif /* WITH_AUDASPACE */
497 
sound_mixdown_invoke(bContext * C,wmOperator * op,const wmEvent * event)498 static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
499 {
500   if (RNA_struct_property_is_set(op->ptr, "filepath")) {
501     return sound_mixdown_exec(C, op);
502   }
503 
504   return WM_operator_filesel(C, op, event);
505 }
506 
507 #ifdef WITH_AUDASPACE
508 
sound_mixdown_draw_check_prop(PointerRNA * UNUSED (ptr),PropertyRNA * prop,void * UNUSED (user_data))509 static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr),
510                                           PropertyRNA *prop,
511                                           void *UNUSED(user_data))
512 {
513   const char *prop_id = RNA_property_identifier(prop);
514   return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") ||
515            STREQ(prop_id, "filename"));
516 }
517 
sound_mixdown_draw(bContext * C,wmOperator * op)518 static void sound_mixdown_draw(bContext *C, wmOperator *op)
519 {
520   static const EnumPropertyItem pcm_format_items[] = {
521       {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"},
522       {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
523 #  ifdef WITH_SNDFILE
524       {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
525 #  endif
526       {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
527       {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"},
528       {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"},
529       {0, NULL, 0, NULL, NULL},
530   };
531 
532   static const EnumPropertyItem mp3_format_items[] = {
533       {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
534       {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
535       {0, NULL, 0, NULL, NULL},
536   };
537 
538 #  ifdef WITH_SNDFILE
539   static const EnumPropertyItem flac_format_items[] = {
540       {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
541       {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
542       {0, NULL, 0, NULL, NULL},
543   };
544 #  endif
545 
546   static const EnumPropertyItem all_codec_items[] = {
547       {AUD_CODEC_AAC, "AAC", 0, "AAC", "Advanced Audio Coding"},
548       {AUD_CODEC_AC3, "AC3", 0, "AC3", "Dolby Digital ATRAC 3"},
549       {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
550       {AUD_CODEC_MP2, "MP2", 0, "MP2", "MPEG-1 Audio Layer II"},
551       {AUD_CODEC_MP3, "MP3", 0, "MP3", "MPEG-2 Audio Layer III"},
552       {AUD_CODEC_PCM, "PCM", 0, "PCM", "Pulse Code Modulation (RAW)"},
553       {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
554       {0, NULL, 0, NULL, NULL},
555   };
556 
557   static const EnumPropertyItem ogg_codec_items[] = {
558       {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
559       {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
560       {0, NULL, 0, NULL, NULL},
561   };
562 
563   uiLayout *layout = op->layout;
564   wmWindowManager *wm = CTX_wm_manager(C);
565   PointerRNA ptr;
566   PropertyRNA *prop_format;
567   PropertyRNA *prop_codec;
568   PropertyRNA *prop_bitrate;
569 
570   uiLayoutSetPropSep(layout, true);
571   uiLayoutSetPropDecorate(layout, false);
572 
573   AUD_Container container = RNA_enum_get(op->ptr, "container");
574   AUD_Codec codec = RNA_enum_get(op->ptr, "codec");
575 
576   prop_format = RNA_struct_find_property(op->ptr, "format");
577   prop_codec = RNA_struct_find_property(op->ptr, "codec");
578   prop_bitrate = RNA_struct_find_property(op->ptr, "bitrate");
579 
580   RNA_def_property_clear_flag(prop_bitrate, PROP_HIDDEN);
581   RNA_def_property_flag(prop_codec, PROP_HIDDEN);
582   RNA_def_property_flag(prop_format, PROP_HIDDEN);
583 
584   switch (container) {
585     case AUD_CONTAINER_AC3:
586       RNA_def_property_enum_items(prop_codec, all_codec_items);
587       RNA_enum_set(op->ptr, "codec", AUD_CODEC_AC3);
588       RNA_enum_set(op->ptr, "format", AUD_FORMAT_FLOAT32);
589       break;
590     case AUD_CONTAINER_FLAC:
591       RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
592       RNA_def_property_enum_items(prop_codec, all_codec_items);
593       RNA_enum_set(op->ptr, "codec", AUD_CODEC_FLAC);
594 #  ifdef WITH_SNDFILE
595       RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
596       RNA_def_property_enum_items(prop_format, flac_format_items);
597 #  else
598       RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
599 #  endif
600       break;
601     case AUD_CONTAINER_MATROSKA:
602       RNA_def_property_clear_flag(prop_codec, PROP_HIDDEN);
603       RNA_def_property_enum_items(prop_codec, all_codec_items);
604 
605       switch (codec) {
606         case AUD_CODEC_AAC:
607           RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
608           break;
609         case AUD_CODEC_AC3:
610           RNA_enum_set(op->ptr, "format", AUD_FORMAT_FLOAT32);
611           break;
612         case AUD_CODEC_FLAC:
613           RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
614           RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
615           break;
616         case AUD_CODEC_MP2:
617           RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
618           break;
619         case AUD_CODEC_MP3:
620           RNA_def_property_enum_items(prop_format, mp3_format_items);
621           RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
622           break;
623         case AUD_CODEC_PCM:
624           RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
625           RNA_def_property_enum_items(prop_format, pcm_format_items);
626           RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
627           break;
628         case AUD_CODEC_VORBIS:
629           RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
630           break;
631         default:
632           break;
633       }
634 
635       break;
636     case AUD_CONTAINER_MP2:
637       RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
638       RNA_enum_set(op->ptr, "codec", AUD_CODEC_MP2);
639       RNA_def_property_enum_items(prop_codec, all_codec_items);
640       break;
641     case AUD_CONTAINER_MP3:
642       RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
643       RNA_def_property_enum_items(prop_format, mp3_format_items);
644       RNA_def_property_enum_items(prop_codec, all_codec_items);
645       RNA_enum_set(op->ptr, "codec", AUD_CODEC_MP3);
646       break;
647     case AUD_CONTAINER_OGG:
648       RNA_def_property_clear_flag(prop_codec, PROP_HIDDEN);
649       RNA_def_property_enum_items(prop_codec, ogg_codec_items);
650       RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
651       break;
652     case AUD_CONTAINER_WAV:
653       RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
654       RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
655       RNA_def_property_enum_items(prop_format, pcm_format_items);
656       RNA_def_property_enum_items(prop_codec, all_codec_items);
657       RNA_enum_set(op->ptr, "codec", AUD_CODEC_PCM);
658       break;
659     default:
660       break;
661   }
662 
663   RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
664 
665   /* main draw call */
666   uiDefAutoButsRNA(
667       layout, &ptr, sound_mixdown_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
668 }
669 #endif /* WITH_AUDASPACE */
670 
SOUND_OT_mixdown(wmOperatorType * ot)671 static void SOUND_OT_mixdown(wmOperatorType *ot)
672 {
673 #ifdef WITH_AUDASPACE
674   static const EnumPropertyItem format_items[] = {
675       {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"},
676       {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
677       {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
678       {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
679       {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"},
680       {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"},
681       {0, NULL, 0, NULL, NULL},
682   };
683 
684   static const EnumPropertyItem codec_items[] = {
685 #  ifdef WITH_FFMPEG
686       {AUD_CODEC_AAC, "AAC", 0, "AAC", "Advanced Audio Coding"},
687       {AUD_CODEC_AC3, "AC3", 0, "AC3", "Dolby Digital ATRAC 3"},
688 #  endif
689       {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
690 #  ifdef WITH_FFMPEG
691       {AUD_CODEC_MP2, "MP2", 0, "MP2", "MPEG-1 Audio Layer II"},
692       {AUD_CODEC_MP3, "MP3", 0, "MP3", "MPEG-2 Audio Layer III"},
693 #  endif
694       {AUD_CODEC_PCM, "PCM", 0, "PCM", "Pulse Code Modulation (RAW)"},
695       {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
696       {0, NULL, 0, NULL, NULL},
697   };
698 
699 #endif /* WITH_AUDASPACE */
700 
701   /* identifiers */
702   ot->name = "Mixdown";
703   ot->description = "Mix the scene's audio to a sound file";
704   ot->idname = "SOUND_OT_mixdown";
705 
706   /* api callbacks */
707   ot->exec = sound_mixdown_exec;
708   ot->invoke = sound_mixdown_invoke;
709 
710 #ifdef WITH_AUDASPACE
711   ot->check = sound_mixdown_check;
712   ot->ui = sound_mixdown_draw;
713 #endif
714   /* flags */
715   ot->flag = OPTYPE_REGISTER;
716 
717   /* properties */
718   WM_operator_properties_filesel(ot,
719                                  FILE_TYPE_FOLDER | FILE_TYPE_SOUND,
720                                  FILE_SPECIAL,
721                                  FILE_SAVE,
722                                  WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
723                                  FILE_DEFAULTDISPLAY,
724                                  FILE_SORT_ALPHA);
725 #ifdef WITH_AUDASPACE
726   RNA_def_int(
727       ot->srna,
728       "accuracy",
729       1024,
730       1,
731       16777216,
732       "Accuracy",
733       "Sample accuracy, important for animation data (the lower the value, the more accurate)",
734       1,
735       16777216);
736   RNA_def_enum(
737       ot->srna, "container", container_items, AUD_CONTAINER_FLAC, "Container", "File format");
738   RNA_def_enum(ot->srna, "codec", codec_items, AUD_CODEC_FLAC, "Codec", "Audio Codec");
739   RNA_def_enum(ot->srna, "format", format_items, AUD_FORMAT_S16, "Format", "Sample format");
740   RNA_def_int(ot->srna, "bitrate", 192, 32, 512, "Bitrate", "Bitrate in kbit/s", 32, 512);
741   RNA_def_boolean(ot->srna,
742                   "split_channels",
743                   0,
744                   "Split channels",
745                   "Each channel will be rendered into a mono file");
746 #endif /* WITH_AUDASPACE */
747 }
748 
749 /* ******************************************************* */
750 
sound_poll(bContext * C)751 static bool sound_poll(bContext *C)
752 {
753   Editing *ed = CTX_data_scene(C)->ed;
754 
755   if (!ed || !ed->act_seq || ed->act_seq->type != SEQ_TYPE_SOUND_RAM) {
756     return false;
757   }
758 
759   return true;
760 }
761 /********************* pack operator *********************/
762 
sound_pack_exec(bContext * C,wmOperator * op)763 static int sound_pack_exec(bContext *C, wmOperator *op)
764 {
765   Main *bmain = CTX_data_main(C);
766   Editing *ed = CTX_data_scene(C)->ed;
767   bSound *sound;
768 
769   if (!ed || !ed->act_seq || ed->act_seq->type != SEQ_TYPE_SOUND_RAM) {
770     return OPERATOR_CANCELLED;
771   }
772 
773   sound = ed->act_seq->sound;
774 
775   if (!sound || sound->packedfile) {
776     return OPERATOR_CANCELLED;
777   }
778 
779   sound->packedfile = BKE_packedfile_new(
780       op->reports, sound->filepath, ID_BLEND_PATH(bmain, &sound->id));
781   BKE_sound_load(bmain, sound);
782 
783   return OPERATOR_FINISHED;
784 }
785 
SOUND_OT_pack(wmOperatorType * ot)786 static void SOUND_OT_pack(wmOperatorType *ot)
787 {
788   /* identifiers */
789   ot->name = "Pack Sound";
790   ot->description = "Pack the sound into the current blend file";
791   ot->idname = "SOUND_OT_pack";
792 
793   /* api callbacks */
794   ot->exec = sound_pack_exec;
795   ot->poll = sound_poll;
796 
797   /* flags */
798   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
799 }
800 
801 /********************* unpack operator *********************/
802 
sound_unpack_exec(bContext * C,wmOperator * op)803 static int sound_unpack_exec(bContext *C, wmOperator *op)
804 {
805   Main *bmain = CTX_data_main(C);
806   int method = RNA_enum_get(op->ptr, "method");
807   bSound *sound = NULL;
808 
809   /* find the supplied image by name */
810   if (RNA_struct_property_is_set(op->ptr, "id")) {
811     char sndname[MAX_ID_NAME - 2];
812     RNA_string_get(op->ptr, "id", sndname);
813     sound = BLI_findstring(&bmain->sounds, sndname, offsetof(ID, name) + 2);
814   }
815 
816   if (!sound || !sound->packedfile) {
817     return OPERATOR_CANCELLED;
818   }
819 
820   if (G.fileflags & G_FILE_AUTOPACK) {
821     BKE_report(op->reports,
822                RPT_WARNING,
823                "AutoPack is enabled, so image will be packed again on file save");
824   }
825 
826   BKE_packedfile_unpack_sound(bmain, op->reports, sound, method);
827 
828   return OPERATOR_FINISHED;
829 }
830 
sound_unpack_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))831 static int sound_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
832 {
833   Editing *ed = CTX_data_scene(C)->ed;
834   bSound *sound;
835 
836   if (RNA_struct_property_is_set(op->ptr, "id")) {
837     return sound_unpack_exec(C, op);
838   }
839 
840   if (!ed || !ed->act_seq || ed->act_seq->type != SEQ_TYPE_SOUND_RAM) {
841     return OPERATOR_CANCELLED;
842   }
843 
844   sound = ed->act_seq->sound;
845 
846   if (!sound || !sound->packedfile) {
847     return OPERATOR_CANCELLED;
848   }
849 
850   if (G.fileflags & G_FILE_AUTOPACK) {
851     BKE_report(op->reports,
852                RPT_WARNING,
853                "AutoPack is enabled, so image will be packed again on file save");
854   }
855 
856   unpack_menu(
857       C, "SOUND_OT_unpack", sound->id.name + 2, sound->filepath, "sounds", sound->packedfile);
858 
859   return OPERATOR_FINISHED;
860 }
861 
SOUND_OT_unpack(wmOperatorType * ot)862 static void SOUND_OT_unpack(wmOperatorType *ot)
863 {
864   /* identifiers */
865   ot->name = "Unpack Sound";
866   ot->description = "Unpack the sound to the samples filename";
867   ot->idname = "SOUND_OT_unpack";
868 
869   /* api callbacks */
870   ot->exec = sound_unpack_exec;
871   ot->invoke = sound_unpack_invoke;
872   ot->poll = sound_poll;
873 
874   /* flags */
875   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
876 
877   /* properties */
878   RNA_def_enum(
879       ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
880   /* XXX, weark!, will fail with library, name collisions */
881   RNA_def_string(
882       ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound data-block name to unpack");
883 }
884 
885 /* ******************************************************* */
886 
ED_operatortypes_sound(void)887 void ED_operatortypes_sound(void)
888 {
889   WM_operatortype_append(SOUND_OT_open);
890   WM_operatortype_append(SOUND_OT_open_mono);
891   WM_operatortype_append(SOUND_OT_mixdown);
892   WM_operatortype_append(SOUND_OT_pack);
893   WM_operatortype_append(SOUND_OT_unpack);
894   WM_operatortype_append(SOUND_OT_update_animation_flags);
895   WM_operatortype_append(SOUND_OT_bake_animation);
896 }
897