1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2015 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer 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 GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/lib/ags_time.h>
21 
22 #include <math.h>
23 
24 #ifdef __APPLE__
25 #include <mach/clock.h>
26 #include <mach/mach.h>
27 #endif
28 
29 /**
30  * SECTION:ags_time
31  * @short_description: utility functions of time
32  * @title: AgsTime
33  * @section_id:
34  * @include: ags/lib/ags_time.h
35  *
36  * Functions to help you dealing with time.
37  */
38 
39 /**
40  * ags_time_get_uptime_from_offset:
41  * @offset: the offset in tics
42  * @bpm: the beats per minute
43  * @delay: the buffer time as delay
44  * @delay_factor: tact segmentation
45  *
46  * Calculates uptime from @offset by applying factors @bpm, @delay and @delay_factor
47  * giving you the result as string.
48  *
49  * Returns: (transfer full): the string containing the time, a minus sign is prepend if factors
50  *   are invalid
51  *
52  * Since: 3.0.0
53  */
54 gchar*
ags_time_get_uptime_from_offset(guint offset,gdouble bpm,gdouble delay,gdouble delay_factor)55 ags_time_get_uptime_from_offset(guint offset,
56 				gdouble bpm,
57 				gdouble delay,
58 				gdouble delay_factor)
59 {
60   gchar *uptime;
61 
62   gdouble delay_min, delay_sec, delay_msec;
63   gdouble tact_redux;
64   guint min, sec, msec;
65 
66   if(bpm <= 0.0 ||
67      delay <= 0.0 ||
68      delay_factor <= 0.0){
69     return(g_strdup_printf("-%s",
70 			   AGS_TIME_ZERO));
71   }
72 
73   /* translate to time string */
74   tact_redux = offset;
75 
76   delay_sec = 16.0 * delay_factor * bpm / 60.0;
77   delay_min = delay_sec * 60.0;
78   delay_msec = delay_sec / 1000.0;
79 
80   min = (guint) floor(tact_redux / delay_min);
81 
82   if(min > 0){
83     tact_redux = tact_redux - (min * delay_min);
84   }
85 
86   sec = (guint) floor(tact_redux / delay_sec);
87 
88   if(sec > 0){
89     tact_redux = tact_redux - (sec * delay_sec);
90   }
91 
92   msec = (guint) floor(tact_redux / delay_msec);
93 
94   uptime = g_strdup_printf("%.4d:%.2d.%.3d", min, sec, msec);
95 
96   return(uptime);
97 }
98 
99 /**
100  * ags_time_timeout_expired:
101  * @start_time: the start time #timespec-struct
102  * @timeout_delay: the delay #timespec-struct
103  *
104  * Check @start_time plus @timeout_delay against current time.
105  *
106  * Returns: %TRUE if timeout expired, otherwise %FALSE
107  *
108  * Since: 3.0.0
109  */
110 gboolean
ags_time_timeout_expired(struct timespec * start_time,struct timespec * timeout_delay)111 ags_time_timeout_expired(struct timespec *start_time,
112 			 struct timespec *timeout_delay)
113 {
114   struct timespec current_time;
115   struct timespec deadline;
116 
117 #ifdef __APPLE__
118   clock_serv_t cclock;
119   mach_timespec_t mts;
120 #endif
121 
122   if(start_time == NULL ||
123      timeout_delay == NULL){
124     return(TRUE);
125   }
126 
127 #ifdef __APPLE__
128   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
129 
130   clock_get_time(cclock, &mts);
131   mach_port_deallocate(mach_task_self(), cclock);
132 
133   current_time.tv_sec = mts.tv_sec;
134   current_time.tv_nsec = mts.tv_nsec;
135 #else
136   clock_gettime(CLOCK_MONOTONIC, &current_time);
137 #endif
138 
139   if(start_time->tv_nsec + timeout_delay->tv_nsec >= AGS_NSEC_PER_SEC){
140     deadline.tv_sec = start_time->tv_sec + timeout_delay->tv_sec + 1;
141     deadline.tv_nsec = (start_time->tv_nsec + timeout_delay->tv_nsec) - AGS_NSEC_PER_SEC;
142   }else{
143     deadline.tv_sec = start_time->tv_sec + timeout_delay->tv_sec;
144     deadline.tv_nsec = start_time->tv_nsec + timeout_delay->tv_nsec;
145   }
146 
147   if(current_time.tv_sec > deadline.tv_sec){
148     return(TRUE);
149   }else{
150     if(current_time.tv_sec == deadline.tv_sec &&
151        current_time.tv_nsec > deadline.tv_nsec){
152       return(TRUE);
153     }
154   }
155 
156   return(FALSE);
157 }
158