Initial commit
[fillmore] / src / fillmore / audio_project.vala
1 /* Copyright 2009-2010 Yorba Foundation
2  *
3  * This software is licensed under the GNU Lesser General Public License
4  * (version 2.1 or later).  See the COPYING file in this distribution. 
5  */
6
7 using Logging;
8 namespace Model {
9
10 class RecordFetcherCompletion : FetcherCompletion {
11     Track track;
12     Project project;
13     int64 position;
14
15     public RecordFetcherCompletion(Project project, Track track, int64 position) {
16         base();
17         this.track = track;
18         this.project = project;
19         this.position = position;
20     }
21
22     public override void complete(Fetcher fetch) {
23         base.complete(fetch);
24         Clip the_clip = new Clip(fetch.clipfile, MediaType.AUDIO, 
25             isolate_filename(fetch.clipfile.filename), 0, 0, fetch.clipfile.length, false);
26         project.undo_manager.start_transaction("Record");
27         track.append_at_time(the_clip, position, true);
28         project.undo_manager.end_transaction("Record");
29     }
30 }
31
32 class AudioProject : Project {
33     bool has_been_saved;
34
35     public AudioProject(string? filename) throws Error {
36         base(filename, false);
37         // TODO: When vala supports throwing from base, remove this check
38         if (this != null) {
39             has_been_saved = filename != null;
40             if (!has_been_saved) {
41                 project_file = generate_filename();
42             }
43             media_engine.callback_pulse.connect(media_engine.on_callback_pulse);
44             media_engine.record_completed.connect(on_record_completed);
45         }
46     }
47
48     public override TimeCode get_clip_time(ClipFile f) {
49         TimeCode t = {};
50         
51         t.get_from_length(f.length);
52         return t;
53     }
54
55     public override string? get_project_file() {
56         if (!has_been_saved) {
57             return null;
58         } else {
59             return base.get_project_file();
60         }
61     }
62
63     string generate_filename() {
64         Time now = Time.local(time_t());
65         string timestring = now.to_string();
66         timestring = timestring.replace(":", "_");
67         string pathname = Path.build_filename(GLib.Environment.get_home_dir(), ".fillmore", 
68             timestring);
69         GLib.DirUtils.create(pathname, 0777);
70         string filename = "%s.%s".printf(timestring, "fill");
71         return Path.build_filename(pathname, filename);
72     }
73
74     public override string get_app_name() {
75         return Recorder.NAME;
76     }
77
78     public override void add_track(Track track) {
79         if (track.media_type() == MediaType.VIDEO) {
80             track.hide();
81             inactive_tracks.add(track);
82             return;
83         }
84         
85         base.add_track(track);
86     }
87     
88     public void record(AudioTrack track) {
89         media_engine.record(track);
90     }
91
92     public void on_record_completed() {
93         emit(this, Facility.SIGNAL_HANDLERS, Level.INFO, "on_record_completed");
94         try {
95             create_clip_fetcher(new Model.RecordFetcherCompletion(this, media_engine.record_track,
96                 media_engine.record_region.start), media_engine.record_region.clipfile.filename);
97         } catch (Error e) {
98             error_occurred("Could not complete recording", e.message);
99         }
100     }
101
102     public override void load(string? filename) {
103         has_been_saved = filename != null;
104         if (!has_been_saved) {
105             project_file = generate_filename();
106         }
107         base.load(filename);
108     }
109
110     public override void save(string? filename) {
111         if (!has_been_saved && filename != null) {
112             move_audio_files(filename);
113             GLib.FileUtils.remove(project_file);
114             GLib.DirUtils.remove(Path.get_dirname(project_file));
115         }
116
117         base.save(filename);
118         has_been_saved = true;
119     }
120
121     void move_audio_files(string filename) {
122         string audio_path = get_audio_path();
123         string destination_path = Path.build_filename(Path.get_dirname(filename), "audio files");
124         GLib.DirUtils.create(destination_path, 0777);
125         GLib.Dir dir;
126         try {
127             dir = Dir.open(audio_path);
128         } catch (FileError e) {
129             return;
130         }
131
132         // First, move all of the files over, even if they aren't currently in the project
133         weak string? base_name = null;
134         do {
135             base_name = dir.read_name();
136             string destination = Path.build_filename(destination_path, base_name);
137             FileUtils.rename(Path.build_filename(audio_path, base_name), destination);
138         } while (base_name != null);
139
140         // Next, update the model so that the project file is saved properly
141         foreach (ClipFile clip_file in clipfiles) {
142             if (Path.get_dirname(clip_file.filename) == audio_path) {
143                 string file_name = Path.get_basename(clip_file.filename);
144                 string destination = Path.build_filename(destination_path, file_name);
145                 clip_file.filename = destination;
146             }
147         }
148
149         GLib.DirUtils.remove(audio_path);
150     }
151
152 }
153 }