218 lines
4.8 KiB
C
218 lines
4.8 KiB
C
/* -*- Mode: C ; c-basic-offset: 2 -*- */
|
|
/*****************************************************************************
|
|
*
|
|
* This file is part of jack_mixer
|
|
*
|
|
* Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
|
|
*
|
|
* This program 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; version 2 of the License
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
|
|
#include "scale.h"
|
|
//#define LOG_LEVEL LOG_LEVEL_DEBUG
|
|
#include "log.h"
|
|
#include "list.h"
|
|
|
|
struct threshold
|
|
{
|
|
struct list_head scale_siblings;
|
|
double db;
|
|
double scale;
|
|
double a;
|
|
double b;
|
|
};
|
|
|
|
struct scale
|
|
{
|
|
struct list_head thresholds;
|
|
double max_db;
|
|
};
|
|
|
|
jack_mixer_scale_t
|
|
scale_create()
|
|
{
|
|
struct scale * scale_ptr;
|
|
|
|
scale_ptr = malloc(sizeof(struct scale));
|
|
if (scale_ptr == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
INIT_LIST_HEAD(&scale_ptr->thresholds);
|
|
scale_ptr->max_db = -INFINITY;
|
|
|
|
LOG_DEBUG("Scale %p created", scale_ptr);
|
|
|
|
return (jack_mixer_scale_t)scale_ptr;
|
|
}
|
|
|
|
#define scale_ptr ((struct scale *)scale)
|
|
|
|
void
|
|
scale_destroy(
|
|
jack_mixer_scale_t scale)
|
|
{
|
|
scale_remove_thresholds(scale);
|
|
free(scale_ptr);
|
|
}
|
|
|
|
void
|
|
scale_remove_thresholds(
|
|
jack_mixer_scale_t scale)
|
|
{
|
|
|
|
struct threshold * threshold_ptr;
|
|
struct threshold * node_ptr;
|
|
|
|
list_for_each_entry_safe(threshold_ptr, node_ptr, &scale_ptr->thresholds, scale_siblings)
|
|
{
|
|
list_del(&(threshold_ptr->scale_siblings));
|
|
free(threshold_ptr);
|
|
threshold_ptr = NULL;
|
|
}
|
|
}
|
|
|
|
bool
|
|
scale_add_threshold(
|
|
jack_mixer_scale_t scale,
|
|
float db,
|
|
float scale_value)
|
|
{
|
|
struct threshold * threshold_ptr;
|
|
|
|
LOG_DEBUG("Adding threshold (%f dBFS -> %f) to scale %p", db, scale, scale_ptr);
|
|
|
|
threshold_ptr = malloc(sizeof(struct threshold));
|
|
LOG_DEBUG("Threshold %p created ", threshold_ptr, db, scale);
|
|
|
|
if (threshold_ptr == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
threshold_ptr->db = db;
|
|
threshold_ptr->scale = scale_value;
|
|
|
|
list_add_tail(&threshold_ptr->scale_siblings, &scale_ptr->thresholds);
|
|
|
|
if (db > scale_ptr->max_db)
|
|
{
|
|
scale_ptr->max_db = db;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#undef threshold_ptr
|
|
|
|
void
|
|
scale_calculate_coefficients(
|
|
jack_mixer_scale_t scale)
|
|
{
|
|
struct threshold * threshold_ptr;
|
|
struct threshold * prev_ptr;
|
|
struct list_head * node_ptr;
|
|
|
|
prev_ptr = NULL;
|
|
|
|
list_for_each(node_ptr, &scale_ptr->thresholds)
|
|
{
|
|
threshold_ptr = list_entry(node_ptr, struct threshold, scale_siblings);
|
|
|
|
LOG_DEBUG("Calculating coefficients for threshold %p", threshold_ptr);
|
|
|
|
if (prev_ptr != NULL)
|
|
{
|
|
threshold_ptr->a = (prev_ptr->scale - threshold_ptr->scale) / (prev_ptr->db - threshold_ptr->db);
|
|
threshold_ptr->b = threshold_ptr->scale - threshold_ptr->a * threshold_ptr->db;
|
|
LOG_DEBUG("%.0f dB - %.0f dB: scale = %f * dB + %f", prev_ptr->db, threshold_ptr->db, threshold_ptr->a, threshold_ptr->b);
|
|
}
|
|
|
|
prev_ptr = threshold_ptr;
|
|
}
|
|
}
|
|
|
|
/* Convert dBFS value to number in range 0.0-1.0 */
|
|
double
|
|
scale_db_to_scale(
|
|
jack_mixer_scale_t scale,
|
|
double db)
|
|
{
|
|
struct threshold * threshold_ptr;
|
|
struct threshold * prev_ptr;
|
|
struct list_head * node_ptr;
|
|
|
|
prev_ptr = NULL;
|
|
|
|
list_for_each(node_ptr, &scale_ptr->thresholds)
|
|
{
|
|
threshold_ptr = list_entry(node_ptr, struct threshold, scale_siblings);
|
|
|
|
if (db < threshold_ptr->db)
|
|
{
|
|
LOG_DEBUG("Match at %f dB treshold", threshold_ptr->db);
|
|
if (prev_ptr == NULL)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
return threshold_ptr->a * db + threshold_ptr->b;
|
|
}
|
|
|
|
prev_ptr = threshold_ptr;
|
|
}
|
|
|
|
return 1.0;
|
|
}
|
|
|
|
/* Convert number in range 0.0-1.0 to dBFS value */
|
|
double
|
|
scale_scale_to_db(
|
|
jack_mixer_scale_t scale,
|
|
double scale_value)
|
|
{
|
|
struct threshold * threshold_ptr;
|
|
struct threshold * prev_ptr;
|
|
struct list_head * node_ptr;
|
|
|
|
prev_ptr = NULL;
|
|
|
|
list_for_each(node_ptr, &scale_ptr->thresholds)
|
|
{
|
|
threshold_ptr = list_entry(node_ptr, struct threshold, scale_siblings);
|
|
|
|
if (scale_value <= threshold_ptr->scale)
|
|
{
|
|
if (prev_ptr == NULL)
|
|
{
|
|
return -INFINITY;
|
|
}
|
|
|
|
return (scale_value - threshold_ptr->b) / threshold_ptr->a;
|
|
}
|
|
|
|
prev_ptr = threshold_ptr;
|
|
}
|
|
|
|
return scale_ptr->max_db;
|
|
}
|