Waveform: Commit a hack-ey for the a/b loop to get updated.
[stretchplayer:stretchplayer.git] / src / Engine.hpp
1 /*
2  * Copyright(c) 2009 by Gabriel M. Beddingfield <gabriel@teuton.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY, without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19 #ifndef ENGINE_HPP
20 #define ENGINE_HPP
21
22 #include <stdint.h>
23 #include <memory>
24 #include <QString>
25 #include <QMutex>
26 #include <QAtomicInt>
27 #include <vector>
28 #include <set>
29
30 namespace StretchPlayer
31 {
32
33 class Configuration;
34 class EngineMessageCallback;
35 class AudioSystem;
36 class RubberBandServer;
37
38 class Engine
39 {
40 public:
41     Engine(Configuration *config = 0);
42     ~Engine();
43
44     QString load_song(const QString& filename);
45     void play();
46     void play_pause();
47     void stop();
48     bool playing() {
49         return _playing;
50     }
51     void loop_ab();
52     bool looping() {
53         return _loop_b > _loop_a;
54     }
55
56     float get_position(); // in seconds
57     float get_length();   // in seconds
58     float get_loop_a();   // in seconds or -1 if not set
59     float get_loop_b();   // in seconds or -1 if not set
60     void set_ab_loop(unsigned long a, unsigned long b);
61     void get_audio_range(double a_secs,
62                          double b_secs,
63                          const float ** left,
64                          const float ** right,
65                          unsigned long *count,
66                          unsigned long *clip_offset);
67     void locate(double secs);
68     float get_stretch() {
69         return _stretch;
70     }
71     void set_stretch(float str) {
72         if(str > 0.5 && str < 2.0) {
73             _stretch = str;
74             //_state_changed = true;
75         }
76     }
77     int get_pitch() {
78         return _pitch;
79     }
80     void set_pitch(int pit) {
81         if(pit < -12) {
82             _pitch = -12;
83         } else if (pit > 12) {
84             _pitch = 12;
85         } else {
86             _pitch = pit;
87         }
88         //_state_changed = true;
89     }
90
91     /**
92      * Clipped to [0.0, 10.0]
93      */
94     void set_volume(float gain) {
95         if(gain < 0.0) gain = 0.0;
96         if(gain > 10.0) gain = 10.0;
97         _gain=gain;
98     }
99
100     float get_volume() {
101         return _gain;
102     }
103
104     /**
105      * Returns estimate of CPU load [0.0, 1.0]
106      */
107     float get_cpu_load();
108
109     void subscribe_errors(EngineMessageCallback* obj) {
110         _subscribe_list(_error_callbacks, obj);
111     }
112     void unsubscribe_errors(EngineMessageCallback* obj) {
113         _unsubscribe_list(_error_callbacks, obj);
114     }
115     void subscribe_messages(EngineMessageCallback* obj) {
116         _subscribe_list(_message_callbacks, obj);
117     }
118     void unsubscribe_messages(EngineMessageCallback* obj) {
119         _unsubscribe_list(_message_callbacks, obj);
120     }
121
122 private:
123     static int static_process_callback(uint32_t nframes, void* arg) {
124         Engine *e = static_cast<Engine*>(arg);
125         return e->process_callback(nframes);
126     }
127     static int static_segment_size_callback(uint32_t nframes, void* arg) {
128         Engine *e = static_cast<Engine*>(arg);
129         return e->segment_size_callback(nframes);
130     }
131
132     int process_callback(uint32_t nframes);
133     int segment_size_callback(uint32_t nframes);
134
135     void _zero_buffers(uint32_t nframes);
136     void _process_playing(uint32_t nframes);
137     void _handle_loop_ab();
138
139     typedef std::set<EngineMessageCallback*> callback_seq_t;
140
141     void _error(const QString& msg) const {
142         _dispatch_message(_error_callbacks, msg);
143     }
144     void _message(const QString& msg) const {
145         _dispatch_message(_message_callbacks, msg);
146     }
147     void _dispatch_message(const callback_seq_t& seq, const QString& msg) const;
148     void _subscribe_list(callback_seq_t& seq, EngineMessageCallback* obj);
149     void _unsubscribe_list(callback_seq_t& seq, EngineMessageCallback* obj);
150
151     Configuration *_config;
152     bool _playing;
153     bool _hit_end;
154     bool _state_changed;
155     mutable QMutex _audio_lock;
156     std::vector<float> _left;
157     std::vector<float> _right;
158     unsigned long _position;
159     unsigned long _loop_a;
160     unsigned long _loop_b;
161     QAtomicInt _loop_ab_pressed;
162     float _sample_rate;
163     float _stretch;
164     int _pitch;
165     float _gain;
166     std::auto_ptr<RubberBandServer> _stretcher;
167     std::auto_ptr<AudioSystem> _audio_system;
168
169     /* Latency tracking */
170     unsigned long _output_position;
171
172     mutable QMutex _callback_lock;
173     callback_seq_t _error_callbacks;
174     callback_seq_t _message_callbacks;
175
176 }; // Engine
177
178 class EngineMessageCallback
179 {
180 public:
181     virtual ~EngineMessageCallback() {
182         if(_parent) {
183             _parent->unsubscribe_errors(this);
184         }
185         if(_parent) {
186             _parent->unsubscribe_messages(this);
187         }
188     }
189
190     virtual void operator()(const QString& message) = 0;
191
192 private:
193     friend class Engine;
194     Engine *_parent;
195 };
196
197 } // namespace StretchPlayer
198
199 #endif // ENGINE_HPP