Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/algo.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ static int compute_period(struct processing_buffers *b, int bph)
if(count > 1)
b->sigma = sqrt((sq_sum - count * estimate * estimate)/ (count-1));
else
b->sigma = b->period;
b->sigma = 0; // No std. dev. estimate possible with just 1 sample
return 0;
}

Expand Down
29 changes: 10 additions & 19 deletions src/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ uint64_t get_timestamp(int light)
return ts;
}

static void fill_buffers(struct processing_buffers *ps, int light)
void fill_buffers(struct processing_buffers *ps, int light)
{
pthread_mutex_lock(&audio_mutex);
uint64_t ts = timestamp;
Expand All @@ -187,26 +187,17 @@ static void fill_buffers(struct processing_buffers *ps, int light)
}
}

int analyze_pa_data(struct processing_data *pd, int bph, double la, uint64_t events_from)
/* Returns if buffer was processed ok */
bool analyze_pa_data(struct processing_data *pd, int step, int bph, double la, uint64_t events_from)
{
struct processing_buffers *p = pd->buffers;
fill_buffers(p, pd->is_light);
struct processing_buffers *p = &pd->buffers[step];

int i;
debug("\nSTART OF COMPUTATION CYCLE\n\n");
for(i=0; i<NSTEPS; i++) {
p[i].last_tic = pd->last_tic;
p[i].events_from = events_from;
process(&p[i], bph, la, pd->is_light);
if( !p[i].ready ) break;
debug("step %d : %f +- %f\n",i,p[i].period/p[i].sample_rate,p[i].sigma/p[i].sample_rate);
}
if(i) {
pd->last_tic = p[i-1].last_tic;
debug("%f +- %f\n",p[i-1].period/p[i-1].sample_rate,p[i-1].sigma/p[i-1].sample_rate);
} else
debug("---\n");
return i;
p->last_tic = pd->last_tic;
p->events_from = events_from;
process(p, bph, la, pd->is_light);
debug("step %d : %f +- %f\n", step, p->period/p->sample_rate, p->sigma/p->sample_rate);

return p->ready;
}

int analyze_pa_data_cal(struct processing_data *pd, struct calibration_data *cd)
Expand Down
45 changes: 36 additions & 9 deletions src/computer.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,45 @@ static void compute_update_cal(struct computer *c)

static void compute_update(struct computer *c)
{
int signal = analyze_pa_data(c->pdata, c->actv->bph, c->actv->la, c->actv->events_from);
struct processing_buffers *p = c->pdata->buffers;
int i;
for(i=0; i<NSTEPS && p[i].ready; i++);
for(i--; i>=0 && p[i].sigma > p[i].period / 10000; i--);
if(i>=0) {
struct processing_data *pd = c->pdata;
struct processing_buffers *ps = pd->buffers;
int step = pd->last_step;

pd->last_step = 0;
/* Do all buffers at once so that all computation interval(s) use the
* same data. Buffers for some intervals will probably not be used, but
* it's not expensive to fill them. Processing is the slow part. */
fill_buffers(ps, pd->is_light);

debug("\nSTART OF COMPUTATION CYCLE\n\n");
unsigned int stepmask = BITMASK(NSTEPS); // Mask of available steps
do {
stepmask &= ~BIT(step);
analyze_pa_data(c->pdata, step, c->actv->bph, c->actv->la, c->actv->events_from);

if (ps[step].ready && ps[step].sigma < ps[step].period / 10000) {
// Try next step if it's available
if (stepmask & BIT(step+1)) step++;
} else {
// This step didn't pass, try a lesser step
step--;
}
} while(step >= 0 && stepmask & BIT(step));

if (step >= 0) {
debug("%f +- %f\n", ps[step].period/ps[step].sample_rate, ps[step].sigma/ps[step].sample_rate);
pd->last_tic = ps[step].last_tic;
pd->last_step = step;

if(c->actv->pb) pb_destroy_clone(c->actv->pb);
c->actv->pb = pb_clone(&p[i]);
c->actv->pb = pb_clone(&ps[step]);
c->actv->is_old = 0;
c->actv->signal = i == NSTEPS-1 && p[i].amp < 0 ? signal-1 : signal;
/* Signal's range is 0 to NSTEPS, while step is -1 to NSTEPS-1, i.e. signal = step+1 */
c->actv->signal = step+1;
} else {
debug("---\n");
c->actv->is_old = 1;
c->actv->signal = -signal;
c->actv->signal = 0;
}
}

Expand Down Expand Up @@ -251,6 +277,7 @@ struct computer *start_computer(int nominal_sr, int bph, double la, int cal, int
pd->buffers = p;
pd->last_tic = 0;
pd->is_light = light;
pd->last_step = 0;

struct calibration_data *cd = malloc(sizeof(struct calibration_data));
setup_cal_data(cd);
Expand Down
24 changes: 17 additions & 7 deletions src/output_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,20 @@ static double amplitude_to_time(double lift_angle, double amp)
return asin(lift_angle / (2 * amp)) / M_PI;
}

static double draw_watch_icon(cairo_t *c, int signal, int happy, int light)
/** Draw the watch graphic that has status info.
*
* @param[in,out] c Cairo context to use.
* @param signal Signal level, i.e. dots, 0 to NSTEPS inclusive.
* @param partial Specified signal level is only partially achieved.
* @param happy Green happy face or red frowny face.
* @param light Indicate light sampling mode.
* @return Y coodinate of top margin.
*/

static double draw_watch_icon(cairo_t *c, int signal, bool partial, bool happy, bool light)
{
happy = !!happy;
cairo_set_line_width(c,3);
cairo_set_source(c,happy?green:red);
cairo_set_line_width(c, 3);
cairo_set_source(c, happy ? green : red);
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.5);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT * 0.75, OUTPUT_WINDOW_HEIGHT * (0.75 - 0.5*happy));
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT * 0.5, OUTPUT_WINDOW_HEIGHT * 0.5);
Expand All @@ -126,15 +135,15 @@ static double draw_watch_icon(cairo_t *c, int signal, int happy, int light)
cairo_stroke(c);
int l = OUTPUT_WINDOW_HEIGHT * 0.8 / (2*NSTEPS - 1);
int i;
cairo_set_line_width(c,1);
cairo_set_line_width(c, 1);
for(i = 0; i < signal; i++) {
cairo_move_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 1.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 1.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - (2*i+1)*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - (2*i+1)*l);
cairo_line_to(c, OUTPUT_WINDOW_HEIGHT + 0.5*l, OUTPUT_WINDOW_HEIGHT * 0.9 - 2*i*l);
cairo_stroke_preserve(c);
cairo_fill(c);
if (i < signal-1 || !partial) cairo_fill(c);
}
if(light) {
int l = OUTPUT_WINDOW_HEIGHT * 0.15;
Expand Down Expand Up @@ -194,7 +203,8 @@ static gboolean output_draw_event(GtkWidget *widget, cairo_t *c, struct output_p
struct processing_buffers *p = snst->pb;
int old = snst->is_old;

double x = draw_watch_icon(c,snst->signal,snst->calibrate ? snst->signal==NSTEPS : snst->signal, snst->is_light);
double x = draw_watch_icon(c, snst->signal, snst->amp <= 0,
snst->signal >= (snst->calibrate ? NSTEPS : 1), snst->is_light);

cairo_text_extents_t extents;

Expand Down
6 changes: 5 additions & 1 deletion src/tg.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
#endif

#define UNUSED(X) (void)(X)
#define BIT(n) (1u << (n))
#define BITMASK(n) ((1u << (n)) - 1u)

/* algo.c */
struct processing_buffers {
Expand Down Expand Up @@ -122,13 +124,15 @@ int process_cal(struct processing_buffers *p, struct calibration_data *cd);
struct processing_data {
struct processing_buffers *buffers;
uint64_t last_tic;
int last_step; //!< Guess of step (buffers index) to try first, based on last iteration
int is_light;
};

int start_portaudio(int *nominal_sample_rate, double *real_sample_rate);
int terminate_portaudio();
uint64_t get_timestamp(int light);
int analyze_pa_data(struct processing_data *pd, int bph, double la, uint64_t events_from);
void fill_buffers(struct processing_buffers *ps, int light);
bool analyze_pa_data(struct processing_data *pd, int step, int bph, double la, uint64_t events_from);
int analyze_pa_data_cal(struct processing_data *pd, struct calibration_data *cd);
void set_audio_light(bool light);

Expand Down