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