File: rateest.c

package info (click to toggle)
mhwaveedit 1.4.9-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 3,316 kB
  • ctags: 2,490
  • sloc: ansic: 22,096; sh: 3,730; makefile: 80; sed: 16
file content (181 lines) | stat: -rw-r--r-- 5,816 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * Copyright (C) 2005, Magnus Hjorth
 *
 * This file is part of mhWaveEdit.
 *
 * mhWaveEdit is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by        
 * the Free Software Foundation; either version 2 of the License, or  
 * (at your option) any later version.
 *
 * mhWaveEdit is distributed in the hope that it will be useful,   
 * but WITHOUT ANY WARRANTY; without even the implied warranty of  
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with mhWaveEdit; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 */


#include <config.h>

#include "rateest.h"

#define BIN_SEC 0.25
#define BIN_USEC 250000
#define BIN_SEC_DIV 4

#define LOW_RATIO_THRESHOLD 0.7
#define HIGH_RATIO_THRESHOLD 1.3

/* The best previous estimate we got so far */
static off_t best_written, best_played;
static gfloat best_seconds;
static gfloat best_discarded_seconds;

/* Total number of frames logged */
static off_t total_written_frames;

/* The value of total_written_frames when the current_* variables were reset */
static off_t current_checkpoint;
/* Time current checkpoint was taken. Also time of last underrun */
static GTimeVal current_checkpoint_time;

/* The current estimation we're building up */
/* Number of frames written for all time intervals that had "normal" usage */
static off_t current_played_frames;
static gfloat current_played_seconds;
/* Number of seconds that were discarded because of too high usage */
static gfloat current_discarded_seconds;

/* Last time period # */
static gboolean is_first_period = TRUE;
static long last_log_period;
/* Amount of data played during this time period */
static off_t current_period_frames;

/* Last value returned by rateest_frames_played */
static off_t last_frames_played_value;


static long calc_current_period(void)
{
     GTimeVal tv;
     g_get_current_time(&tv);
     return tv.tv_sec*BIN_SEC_DIV + tv.tv_usec/BIN_USEC;
}

void rateest_init(guint expected_samplerate)
{
     best_written = best_played = (gfloat)expected_samplerate;
     best_seconds = 1.0;
     total_written_frames = 0;
     current_checkpoint = 0;
     g_get_current_time(&current_checkpoint_time);
     current_played_frames = 0;
     current_played_seconds = 0;
     last_log_period = calc_current_period();
     is_first_period = TRUE;
     current_period_frames = 0;
     last_frames_played_value = 0;     
}

void rateest_log_data(guint frames)
{
     long l;
     gfloat ratio;

     l = calc_current_period();
     if (l != last_log_period) {

	  ratio = ((gfloat)(current_period_frames * BIN_SEC_DIV)) /
	       (best_played / best_seconds);
	  /* printf("Period finished: frames=%d, ratio=%f\n",
	     (int)current_period_frames,ratio); */

	  /* Ignore the first period, since it has unknown length */
	  if (is_first_period) {
	       current_discarded_seconds += current_period_frames / 
		    rateest_real_samplerate();
	  } else if (l < last_log_period || (l-last_log_period > 1) || 
		     ratio < LOW_RATIO_THRESHOLD) {
	       /* Store the current estimate as the best if it is */
	       if (current_played_seconds > best_seconds) {
		    best_written = (gfloat)(total_written_frames-
					    current_checkpoint);
		    best_played = current_played_frames;
		    best_seconds = current_played_seconds;
		    best_discarded_seconds = current_discarded_seconds;
	       }
	       current_checkpoint = total_written_frames;
	       g_get_current_time(&current_checkpoint_time);
	       current_played_frames = 0;
	       current_played_seconds = 0.0;
	       current_discarded_seconds = 0.0;
	  } else if (ratio < HIGH_RATIO_THRESHOLD) {
	       /* Add this period to the current estimation */
	       current_played_frames += current_period_frames;
	       current_played_seconds += BIN_SEC;
	  } else
	       current_discarded_seconds += BIN_SEC;
	  current_period_frames = 0;
	  last_log_period = l;
     }

     current_period_frames += frames;
     total_written_frames += frames;
}

void rateest_prelog_data(guint frames)
{
     total_written_frames += frames;
}

off_t rateest_frames_written(void)
{
     return total_written_frames;
}

gfloat rateest_real_samplerate(void)
{
     if (best_seconds > current_played_seconds)
	  return ((gfloat)best_played)/best_seconds;
     else
	  return ((gfloat)current_played_frames)/current_played_seconds;
}

off_t rateest_frames_played(void)
{
     GTimeVal tv,tv2;
     int i;
     gfloat f,sr;
     off_t o,lat;
     /* First, use clock time, checkpoint time and estimated sample
      * rate to calculate position. 
      * If the clock seems broken, use written frames and estimated latency. */
     g_get_current_time(&tv);
     i = timeval_subtract(&tv2,&tv,&current_checkpoint_time);
     sr = rateest_real_samplerate();
     if (i >= 0) {
	  /* printf("tv2: %ld.%6ld\n",tv2.tv_sec,tv2.tv_usec); */
	  f = (gfloat)tv2.tv_usec * 0.000001 + (gfloat)tv2.tv_sec;
	  f *= sr;
	  /* printf("f: %f, sr: %f\n",f,sr); */
	  o = current_checkpoint + (off_t)f;
	  /* printf("First guess: %d, total_written: %d\n",(int)o,
	     (int)total_written_frames); */
	  if (o>total_written_frames) o=total_written_frames;
     }
     if (i<0) {	  
	  if (best_seconds > current_played_seconds)
	       lat = best_written - (best_seconds + best_discarded_seconds)*sr;
	  else
	       lat = (total_written_frames - current_checkpoint) - 
		    (current_played_seconds + current_discarded_seconds)*sr;
	  o = total_written_frames - lat;	  
     }
     if (o > last_frames_played_value) last_frames_played_value = o;
     return last_frames_played_value;
}