be4f6ff0570d3ba53c91fca6b377978bedb63a4c
[blender-staging.git] / source / blender / editors / sound / sound_ops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_packedFile_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_sequence_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_main.h"
44 #include "BKE_report.h"
45 #include "BKE_packedFile.h"
46 #include "BKE_sound.h"
47 #include "BKE_utildefines.h"
48
49 #include "BLI_blenlib.h"
50
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 #include "AUD_C-API.h"
62
63 #include "sound_intern.h"
64
65 /******************** open sound operator ********************/
66
67 static void open_init(bContext *C, wmOperator *op)
68 {
69         PropertyPointerRNA *pprop;
70         
71         op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
72         uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
73 }
74
75 static int open_exec(bContext *C, wmOperator *op)
76 {
77         char path[FILE_MAX];
78         bSound *sound;
79         PropertyPointerRNA *pprop;
80         PointerRNA idptr;
81         AUD_SoundInfo info;
82
83         RNA_string_get(op->ptr, "path", path);
84         sound = sound_new_file(CTX_data_main(C), path);
85
86         if(!op->customdata)
87                 open_init(C, op);
88         
89         if (sound==NULL || sound->playback_handle == NULL) {
90                 if(op->customdata) MEM_freeN(op->customdata);
91                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
92                 return OPERATOR_CANCELLED;
93         }
94
95         info = AUD_getInfo(sound->playback_handle);
96
97         if (info.specs.channels == AUD_CHANNELS_INVALID) {
98                 sound_delete(C, sound);
99                 if(op->customdata) MEM_freeN(op->customdata);
100                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
101                 return OPERATOR_CANCELLED;
102         }
103
104         if (RNA_boolean_get(op->ptr, "cache")) {
105                 sound_cache(sound, 0);
106         }
107         
108         /* hook into UI */
109         pprop= op->customdata;
110         
111         if(pprop->prop) {
112                 /* when creating new ID blocks, use is already 1, but RNA
113                  * pointer se also increases user, so this compensates it */
114                 sound->id.us--;
115                 
116                 RNA_id_pointer_create(&sound->id, &idptr);
117                 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
118                 RNA_property_update(C, &pprop->ptr, pprop->prop);
119         }
120
121         MEM_freeN(op->customdata);
122         return OPERATOR_FINISHED;
123 }
124
125 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
126 {
127         if(!RNA_property_is_set(op->ptr, "relative_path"))
128                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
129         
130         if(RNA_property_is_set(op->ptr, "path"))
131                 return open_exec(C, op);
132         
133         open_init(C, op);
134         
135         return WM_operator_filesel(C, op, event);
136 }
137
138 void SOUND_OT_open(wmOperatorType *ot)
139 {
140         /* identifiers */
141         ot->name= "Open Sound";
142         ot->description= "Load a sound file";
143         ot->idname= "SOUND_OT_open";
144
145         /* api callbacks */
146         ot->exec= open_exec;
147         ot->invoke= open_invoke;
148
149         /* flags */
150         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
151
152         /* properties */
153         WM_operator_properties_filesel(ot, FOLDERFILE|SOUNDFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE);
154         RNA_def_boolean(ot->srna, "cache", FALSE, "Cache", "Cache the sound in memory.");
155         RNA_def_boolean(ot->srna, "relative_path", FALSE, "Relative Path", "Load image with relative path to current .blend file");
156 }
157
158 /* ******************************************************* */
159
160 static int sound_poll(bContext *C)
161 {
162         Editing* ed = CTX_data_scene(C)->ed;
163
164         if(!ed || !ed->act_seq || ed->act_seq->type != SEQ_SOUND)
165                 return 0;
166
167         return 1;
168 }
169 /********************* pack operator *********************/
170
171 static int pack_exec(bContext *C, wmOperator *op)
172 {
173         Editing* ed = CTX_data_scene(C)->ed;
174         bSound* sound;
175
176         if(!ed || !ed->act_seq || ed->act_seq->type != SEQ_SOUND)
177                 return OPERATOR_CANCELLED;
178
179         sound = ed->act_seq->sound;
180
181         if(!sound || sound->packedfile)
182                 return OPERATOR_CANCELLED;
183
184         sound->packedfile= newPackedFile(op->reports, sound->name);
185         sound_load(CTX_data_main(C), sound);
186
187         return OPERATOR_FINISHED;
188 }
189
190 void SOUND_OT_pack(wmOperatorType *ot)
191 {
192         /* identifiers */
193         ot->name= "Pack Sound";
194         ot->description= "Pack the sound into the current blend file";
195         ot->idname= "SOUND_OT_pack";
196
197         /* api callbacks */
198         ot->exec= pack_exec;
199         ot->poll= sound_poll;
200
201         /* flags */
202         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
203 }
204
205 /********************* unpack operator *********************/
206
207 // XXX this function is in image_ops.c too, exactly the same, should be moved to a generally accessible position
208 static void unpack_menu(bContext *C, char *opname, char *abs_name, char *folder, PackedFile *pf)
209 {
210         uiPopupMenu *pup;
211         uiLayout *layout;
212         char line[FILE_MAX + 100];
213         char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
214
215         strcpy(local_name, abs_name);
216         BLI_splitdirstring(local_name, fi);
217         sprintf(local_name, "//%s/%s", folder, fi);
218
219         pup= uiPupMenuBegin(C, "Unpack file", 0);
220         layout= uiPupMenuLayout(pup);
221
222         uiItemEnumO(layout, opname, "Remove Pack", 0, "method", PF_REMOVE);
223
224         if(strcmp(abs_name, local_name)) {
225                 switch(checkPackedFile(local_name, pf)) {
226                         case PF_NOFILE:
227                                 sprintf(line, "Create %s", local_name);
228                                 uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_LOCAL);
229                                 break;
230                         case PF_EQUAL:
231                                 sprintf(line, "Use %s (identical)", local_name);
232                                 uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
233                                 break;
234                         case PF_DIFFERS:
235                                 sprintf(line, "Use %s (differs)", local_name);
236                                 uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
237                                 sprintf(line, "Overwrite %s", local_name);
238                                 uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_LOCAL);
239                                 break;
240                 }
241         }
242
243         switch(checkPackedFile(abs_name, pf)) {
244                 case PF_NOFILE:
245                         sprintf(line, "Create %s", abs_name);
246                         uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
247                         break;
248                 case PF_EQUAL:
249                         sprintf(line, "Use %s (identical)", abs_name);
250                         uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
251                         break;
252                 case PF_DIFFERS:
253                         sprintf(line, "Use %s (differs)", local_name);
254                         uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
255                         sprintf(line, "Overwrite %s", local_name);
256                         uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
257                         break;
258         }
259
260         uiPupMenuEnd(C, pup);
261 }
262
263 static int unpack_exec(bContext *C, wmOperator *op)
264 {
265         int method= RNA_enum_get(op->ptr, "method");
266         Editing* ed = CTX_data_scene(C)->ed;
267         bSound* sound;
268
269         if(!ed || !ed->act_seq || ed->act_seq->type != SEQ_SOUND)
270                 return OPERATOR_CANCELLED;
271
272         sound = ed->act_seq->sound;
273
274         if(!sound || !sound->packedfile)
275                 return OPERATOR_CANCELLED;
276
277         if(G.fileflags & G_AUTOPACK)
278                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
279
280         unpackSound(op->reports, sound, method);
281
282         return OPERATOR_FINISHED;
283 }
284
285 static int unpack_invoke(bContext *C, wmOperator *op, wmEvent *event)
286 {
287         Editing* ed = CTX_data_scene(C)->ed;
288         bSound* sound;
289
290         if(!ed || !ed->act_seq || ed->act_seq->type != SEQ_SOUND)
291                 return OPERATOR_CANCELLED;
292
293         sound = ed->act_seq->sound;
294
295         if(!sound || !sound->packedfile)
296                 return OPERATOR_CANCELLED;
297
298         if(G.fileflags & G_AUTOPACK)
299                 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
300
301         unpack_menu(C, "SOUND_OT_unpack", sound->name, "audio", sound->packedfile);
302
303         return OPERATOR_FINISHED;
304 }
305
306 void SOUND_OT_unpack(wmOperatorType *ot)
307 {
308         /* identifiers */
309         ot->name= "Unpack Sound";
310         ot->description= "Unpack the sound to the samples filename";
311         ot->idname= "SOUND_OT_unpack";
312
313         /* api callbacks */
314         ot->exec= unpack_exec;
315         ot->invoke= unpack_invoke;
316         ot->poll= sound_poll;
317
318         /* flags */
319         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
320
321         /* properties */
322         RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack.");
323 }
324
325 /* ******************************************************* */
326
327 void ED_operatortypes_sound(void)
328 {
329         WM_operatortype_append(SOUND_OT_open);
330         WM_operatortype_append(SOUND_OT_pack);
331         WM_operatortype_append(SOUND_OT_unpack);
332 }