1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Vamp
5 
6     An API for audio analysis and feature extraction plugins.
7 
8     Centre for Digital Music, Queen Mary, University of London.
9     Copyright 2006 Chris Cannam.
10 
11     Permission is hereby granted, free of charge, to any person
12     obtaining a copy of this software and associated documentation
13     files (the "Software"), to deal in the Software without
14     restriction, including without limitation the rights to use, copy,
15     modify, merge, publish, distribute, sublicense, and/or sell copies
16     of the Software, and to permit persons to whom the Software is
17     furnished to do so, subject to the following conditions:
18 
19     The above copyright notice and this permission notice shall be
20     included in all copies or substantial portions of the Software.
21 
22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 
30     Except as contained in this notice, the names of the Centre for
31     Digital Music; Queen Mary, University of London; and Chris Cannam
32     shall not be used in advertising or otherwise to promote the sale,
33     use or other dealings in this Software without prior written
34     authorization.
35 */
36 
37 /*
38    This is a modified version of a source file from the
39    Rosegarden MIDI and audio sequencer and notation editor.
40    This file copyright 2000-2006 Chris Cannam.
41    Relicensed by the author as detailed above.
42 */
43 
44 #include <iostream>
45 #include <limits.h>
46 
47 #if (defined(__GNUC__)) && (__GNUC__ < 3)
48 #include <strstream>
49 #define stringstream strstream
50 #else
51 #include <sstream>
52 #endif
53 
54 using std::cerr;
55 using std::endl;
56 
57 #ifndef _WIN32
58 #include <sys/time.h>
59 #endif
60 
61 #include <vamp-sdk/RealTime.h>
62 
63 _VAMP_SDK_PLUGSPACE_BEGIN(RealTime.cpp)
64 
65 namespace Vamp {
66 
67 // A RealTime consists of two ints that must be at least 32 bits each.
68 // A signed 32-bit int can store values exceeding +/- 2 billion.  This
69 // means we can safely use our lower int for nanoseconds, as there are
70 // 1 billion nanoseconds in a second and we need to handle double that
71 // because of the implementations of addition etc that we use.
72 //
73 // The maximum valid RealTime on a 32-bit system is somewhere around
74 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
75 
76 #define ONE_BILLION 1000000000
77 
RealTime(int s,int n)78 RealTime::RealTime(int s, int n) :
79     sec(s), nsec(n)
80 {
81     while (nsec <= -ONE_BILLION && sec > INT_MIN) { nsec += ONE_BILLION; --sec; }
82     while (nsec >=  ONE_BILLION && sec < INT_MAX) { nsec -= ONE_BILLION; ++sec; }
83     while (nsec > 0 && sec < 0) { nsec -= ONE_BILLION; ++sec; }
84     while (nsec < 0 && sec > 0) { nsec += ONE_BILLION; --sec; }
85 }
86 
87 RealTime
fromSeconds(double sec)88 RealTime::fromSeconds(double sec)
89 {
90     if (sec != sec) { // NaN
91         cerr << "ERROR: NaN/Inf passed to Vamp::RealTime::fromSeconds" << endl;
92         return RealTime::zeroTime;
93     } else if (sec >= 0) {
94         return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
95     } else {
96         return -fromSeconds(-sec);
97     }
98 }
99 
100 RealTime
fromMilliseconds(int msec)101 RealTime::fromMilliseconds(int msec)
102 {
103     return RealTime(msec / 1000, (msec % 1000) * 1000000);
104 }
105 
106 #ifndef _WIN32
107 RealTime
fromTimeval(const struct timeval & tv)108 RealTime::fromTimeval(const struct timeval &tv)
109 {
110     return RealTime(int(tv.tv_sec), int(tv.tv_usec * 1000));
111 }
112 #endif
113 
operator <<(std::ostream & out,const RealTime & rt)114 std::ostream &operator<<(std::ostream &out, const RealTime &rt)
115 {
116     if (rt < RealTime::zeroTime) {
117 	out << "-";
118     } else {
119 	out << " ";
120     }
121 
122     int s = (rt.sec < 0 ? -rt.sec : rt.sec);
123     int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
124 
125     out << s << ".";
126 
127     int nn(n);
128     if (nn == 0) out << "00000000";
129     else while (nn < (ONE_BILLION / 10)) {
130 	out << "0";
131 	nn *= 10;
132     }
133 
134     out << n << "R";
135     return out;
136 }
137 
138 std::string
toString() const139 RealTime::toString() const
140 {
141     std::stringstream out;
142     out << *this;
143 
144     std::string s = out.str();
145 
146     // remove trailing R
147     return s.substr(0, s.length() - 1);
148 }
149 
150 std::string
toText(bool fixedDp) const151 RealTime::toText(bool fixedDp) const
152 {
153     if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp);
154 
155     std::stringstream out;
156 
157     if (sec >= 3600) {
158         out << (sec / 3600) << ":";
159     }
160 
161     if (sec >= 60) {
162         int minutes = (sec % 3600) / 60;
163         if (sec >= 3600 && minutes < 10) out << "0";
164         out << minutes << ":";
165     }
166 
167     if (sec >= 10) {
168         out << ((sec % 60) / 10);
169     }
170 
171     out << (sec % 10);
172 
173     int ms = msec();
174 
175     if (ms != 0) {
176 	out << ".";
177 	out << (ms / 100);
178 	ms = ms % 100;
179 	if (ms != 0) {
180 	    out << (ms / 10);
181 	    ms = ms % 10;
182 	} else if (fixedDp) {
183 	    out << "0";
184 	}
185 	if (ms != 0) {
186 	    out << ms;
187 	} else if (fixedDp) {
188 	    out << "0";
189 	}
190     } else if (fixedDp) {
191 	out << ".000";
192     }
193 
194     std::string s = out.str();
195 
196     return s;
197 }
198 
199 RealTime
operator /(int d) const200 RealTime::operator/(int d) const
201 {
202     int secdiv = sec / d;
203     int secrem = sec % d;
204 
205     double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
206 
207     return RealTime(secdiv, int(nsecdiv + 0.5));
208 }
209 
210 double
operator /(const RealTime & r) const211 RealTime::operator/(const RealTime &r) const
212 {
213     double lTotal = double(sec) * ONE_BILLION + double(nsec);
214     double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
215 
216     if (rTotal == 0) return 0.0;
217     else return lTotal/rTotal;
218 }
219 
220 long
realTime2Frame(const RealTime & time,unsigned int sampleRate)221 RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
222 {
223     if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
224     double s = time.sec + double(time.nsec) / ONE_BILLION;
225     return long(s * sampleRate + 0.5);
226 }
227 
228 RealTime
frame2RealTime(long frame,unsigned int sampleRate)229 RealTime::frame2RealTime(long frame, unsigned int sampleRate)
230 {
231     if (frame < 0) return -frame2RealTime(-frame, sampleRate);
232 
233     int sec = int(frame / long(sampleRate));
234     frame -= sec * long(sampleRate);
235     int nsec = (int)((double(frame) / double(sampleRate)) * ONE_BILLION + 0.5);
236     // Use ctor here instead of setting data members directly to
237     // ensure nsec > ONE_BILLION is handled properly.  It's extremely
238     // unlikely, but not impossible.
239     return RealTime(sec, nsec);
240 }
241 
242 const RealTime RealTime::zeroTime(0,0);
243 
244 }
245 
246 _VAMP_SDK_PLUGSPACE_END(RealTime.cpp)
247 
248 
249 
250