/* GSequencer - Advanced GTK Sequencer
* Copyright (C) 2005-2021 Joël Krähemann
*
* This file is part of GSequencer.
*
* GSequencer 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 3 of the License, or
* (at your option) any later version.
*
* GSequencer 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 GSequencer. If not, see .
*/
#include
#include
#include
#include
/**
* SECTION:ags_hq_pitch_util
* @short_description: hq pitch util
* @title: AgsHQPitchUtil
* @section_id:
* @include: ags/audio/ags_hq_pitch_util.h
*
* Utility functions to pitch.
*/
GType
ags_hq_pitch_util_get_type(void)
{
static volatile gsize g_define_type_id__volatile = 0;
if(g_once_init_enter (&g_define_type_id__volatile)){
GType ags_type_hq_pitch_util = 0;
ags_type_hq_pitch_util =
g_boxed_type_register_static("AgsHQPitchUtil",
(GBoxedCopyFunc) ags_hq_pitch_util_copy,
(GBoxedFreeFunc) ags_hq_pitch_util_free);
g_once_init_leave(&g_define_type_id__volatile, ags_type_hq_pitch_util);
}
return g_define_type_id__volatile;
}
/**
* ags_hq_pitch_util_alloc:
*
* Allocate #AgsHQPitchUtil-struct.
*
* Returns: the newly allocated #AgsHQPitchUtil-struct
*
* Since: 3.9.6
*/
AgsHQPitchUtil*
ags_hq_pitch_util_alloc()
{
AgsHQPitchUtil *ptr;
ptr = (AgsHQPitchUtil *) g_new(AgsHQPitchUtil,
1);
ptr->source = NULL;
ptr->source_stride = 1;
ptr->destination = NULL;
ptr->destination_stride = 1;
ptr->low_mix_buffer = NULL;
ptr->new_mix_buffer = NULL;
ptr->buffer_length = 0;
ptr->format = AGS_SOUNDCARD_DEFAULT_FORMAT;
ptr->samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
ptr->base_key = 0.0;
ptr->tuning = 0.0;
return(ptr);
}
/**
* ags_hq_pitch_util_copy:
* @ptr: the original #AgsHQPitchUtil-struct
*
* Create a copy of @ptr.
*
* Returns: a pointer of the new #AgsHQPitchUtil-struct
*
* Since: 3.9.6
*/
gpointer
ags_hq_pitch_util_copy(AgsHQPitchUtil *ptr)
{
AgsHQPitchUtil *new_ptr;
new_ptr = (AgsHQPitchUtil *) g_new(AgsHQPitchUtil,
1);
new_ptr->destination = ptr->destination;
new_ptr->destination_stride = ptr->destination_stride;
new_ptr->source = ptr->source;
new_ptr->source_stride = ptr->source_stride;
new_ptr->low_mix_buffer = NULL;
new_ptr->new_mix_buffer = NULL;
if(ptr->buffer_length > 0){
new_ptr->low_mix_buffer = ags_stream_alloc(ptr->buffer_length,
ptr->format);
new_ptr->new_mix_buffer = ags_stream_alloc(ptr->buffer_length,
ptr->format);
}
new_ptr->buffer_length = ptr->buffer_length;
new_ptr->format = ptr->format;
new_ptr->samplerate = ptr->samplerate;
new_ptr->base_key = ptr->base_key;
new_ptr->tuning = ptr->tuning;
return(new_ptr);
}
/**
* ags_hq_pitch_util_free:
* @ptr: the #AgsHQPitchUtil-struct
*
* Free the memory of @ptr.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_free(AgsHQPitchUtil *ptr)
{
g_free(ptr->destination);
if(ptr->destination != ptr->source){
g_free(ptr->source);
}
g_free(ptr->low_mix_buffer);
g_free(ptr->new_mix_buffer);
g_free(ptr);
}
/**
* ags_hq_pitch_util_get_destination:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get destination buffer of @hq_pitch_util.
*
* Returns: the destination buffer
*
* Since: 3.9.6
*/
gpointer
ags_hq_pitch_util_get_destination(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(NULL);
}
return(hq_pitch_util->destination);
}
/**
* ags_hq_pitch_util_set_destination:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @destination: the destination buffer
*
* Set @destination buffer of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_destination(AgsHQPitchUtil *hq_pitch_util,
gpointer destination)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->destination = destination;
}
/**
* ags_hq_pitch_util_get_destination_stride:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get destination stride of @hq_pitch_util.
*
* Returns: the destination buffer stride
*
* Since: 3.9.6
*/
guint
ags_hq_pitch_util_get_destination_stride(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0);
}
return(hq_pitch_util->destination_stride);
}
/**
* ags_hq_pitch_util_set_destination_stride:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @destination_stride: the destination buffer stride
*
* Set @destination stride of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_destination_stride(AgsHQPitchUtil *hq_pitch_util,
guint destination_stride)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->destination_stride = destination_stride;
}
/**
* ags_hq_pitch_util_get_source:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get source buffer of @hq_pitch_util.
*
* Returns: the source buffer
*
* Since: 3.9.6
*/
gpointer
ags_hq_pitch_util_get_source(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(NULL);
}
return(hq_pitch_util->source);
}
/**
* ags_hq_pitch_util_set_source:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @source: the source buffer
*
* Set @source buffer of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_source(AgsHQPitchUtil *hq_pitch_util,
gpointer source)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->source = source;
}
/**
* ags_hq_pitch_util_get_source_stride:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get source stride of @hq_pitch_util.
*
* Returns: the source buffer stride
*
* Since: 3.9.6
*/
guint
ags_hq_pitch_util_get_source_stride(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0);
}
return(hq_pitch_util->source_stride);
}
/**
* ags_hq_pitch_util_set_source_stride:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @source_stride: the source buffer stride
*
* Set @source stride of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_source_stride(AgsHQPitchUtil *hq_pitch_util,
guint source_stride)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->source_stride = source_stride;
}
/**
* ags_hq_pitch_util_get_buffer_length:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get buffer length of @hq_pitch_util.
*
* Returns: the buffer length
*
* Since: 3.9.6
*/
guint
ags_hq_pitch_util_get_buffer_length(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0);
}
return(hq_pitch_util->buffer_length);
}
/**
* ags_hq_pitch_util_set_buffer_length:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @buffer_length: the buffer length
*
* Set @buffer_length of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_buffer_length(AgsHQPitchUtil *hq_pitch_util,
guint buffer_length)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->buffer_length = buffer_length;
ags_stream_free(hq_pitch_util->low_mix_buffer);
ags_stream_free(hq_pitch_util->new_mix_buffer);
hq_pitch_util->low_mix_buffer = NULL;
hq_pitch_util->new_mix_buffer = NULL;
if(buffer_length > 0){
hq_pitch_util->low_mix_buffer = ags_stream_alloc(buffer_length,
hq_pitch_util->format);
hq_pitch_util->new_mix_buffer = ags_stream_alloc(buffer_length,
hq_pitch_util->format);
}
}
/**
* ags_hq_pitch_util_get_format:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get format of @hq_pitch_util.
*
* Returns: the format
*
* Since: 3.9.6
*/
guint
ags_hq_pitch_util_get_format(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0);
}
return(hq_pitch_util->format);
}
/**
* ags_hq_pitch_util_set_format:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @format: the format
*
* Set @format of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_format(AgsHQPitchUtil *hq_pitch_util,
guint format)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->format = format;
ags_stream_free(hq_pitch_util->low_mix_buffer);
ags_stream_free(hq_pitch_util->new_mix_buffer);
hq_pitch_util->low_mix_buffer = NULL;
hq_pitch_util->new_mix_buffer = NULL;
if(hq_pitch_util->buffer_length > 0){
hq_pitch_util->low_mix_buffer = ags_stream_alloc(hq_pitch_util->buffer_length,
format);
hq_pitch_util->new_mix_buffer = ags_stream_alloc(hq_pitch_util->buffer_length,
format);
}
}
/**
* ags_hq_pitch_util_get_samplerate:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get samplerate of @hq_pitch_util.
*
* Returns: the samplerate
*
* Since: 3.9.6
*/
guint
ags_hq_pitch_util_get_samplerate(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0);
}
return(hq_pitch_util->samplerate);
}
/**
* ags_hq_pitch_util_set_samplerate:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @samplerate: the samplerate
*
* Set @samplerate of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_samplerate(AgsHQPitchUtil *hq_pitch_util,
guint samplerate)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->samplerate = samplerate;
}
/**
* ags_hq_pitch_util_get_base_key:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get base key of @hq_pitch_util.
*
* Returns: the base key
*
* Since: 3.9.6
*/
gdouble
ags_hq_pitch_util_get_base_key(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0.0);
}
return(hq_pitch_util->base_key);
}
/**
* ags_hq_pitch_util_set_base_key:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @base_key: the base key
*
* Set @base_key of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_base_key(AgsHQPitchUtil *hq_pitch_util,
gdouble base_key)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->base_key = base_key;
}
/**
* ags_hq_pitch_util_get_tuning:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Get tuning of @hq_pitch_util.
*
* Returns: the tuning
*
* Since: 3.9.6
*/
gdouble
ags_hq_pitch_util_get_tuning(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL){
return(0.0);
}
return(hq_pitch_util->tuning);
}
/**
* ags_hq_pitch_util_set_tuning:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
* @tuning: the tuning
*
* Set @tuning of @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_set_tuning(AgsHQPitchUtil *hq_pitch_util,
gdouble tuning)
{
if(hq_pitch_util == NULL){
return;
}
hq_pitch_util->tuning = tuning;
}
/**
* ags_hq_pitch_util_pitch_s8:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of signed 8 bit data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_s8(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gint8 *destination, *source;
gint8 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint8 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gint8 *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gint8 *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_SIGNED_8_BIT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint8 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_s16:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of signed 16 bit data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_s16(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gint16 *destination, *source;
gint16 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint16 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gint16 *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gint16 *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_SIGNED_16_BIT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint16 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_s24:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of signed 24 bit data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_s24(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gint32 *destination, *source;
gint32 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint32 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gint32 *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gint32 *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_SIGNED_24_BIT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint32 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_s32:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of signed 32 bit data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_s32(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gint32 *destination, *source;
gint32 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint32 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gint32 *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gint32 *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_SIGNED_32_BIT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint32 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_s64:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of signed 64 bit data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_s64(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gint64 *destination, *source;
gint64 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint64 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gint64 *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gint64 *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_SIGNED_64_BIT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint64 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_float:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of floating point data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_float(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gfloat *destination, *source;
gfloat *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gfloat *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gfloat *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gfloat *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_FLOAT);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gfloat new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_double:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of double precision floating point data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_double(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
gdouble *destination, *source;
gdouble *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gdouble *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (gdouble *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (gdouble *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_DOUBLE);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gdouble new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
destination[i * destination_stride] = new_mix_buffer[i];
}
}
/**
* ags_hq_pitch_util_pitch_complex:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util of complex data.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch_complex(AgsHQPitchUtil *hq_pitch_util)
{
AgsLinearInterpolateUtil *linear_interpolate_util;
AgsComplex *destination, *source;
AgsComplex *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
AgsComplex *mix_buffer, *new_mix_buffer, *low_mix_buffer;
guint destination_stride, source_stride;
guint buffer_length;
guint samplerate;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
linear_interpolate_util = hq_pitch_util->linear_interpolate_util;
destination = hq_pitch_util->destination;
destination_stride = hq_pitch_util->destination_stride;
source = hq_pitch_util->source;
source_stride = hq_pitch_util->source_stride;
buffer_length = hq_pitch_util->buffer_length;
samplerate = hq_pitch_util->samplerate;
/* frequency */
base_freq = exp2((hq_pitch_util->base_key) / 12.0) * 440.0;
new_freq = exp2((hq_pitch_util->base_key + (hq_pitch_util->tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((hq_pitch_util->base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(hq_pitch_util->tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* get buffer */
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
mix_buffer = source;
low_mix_buffer = (AgsComplex *) hq_pitch_util->low_mix_buffer;
new_mix_buffer = (AgsComplex *) hq_pitch_util->new_mix_buffer;
ags_linear_interpolate_util_set_destination(linear_interpolate_util,
low_mix_buffer);
ags_linear_interpolate_util_set_source(linear_interpolate_util,
source);
ags_linear_interpolate_util_set_buffer_length(linear_interpolate_util,
low_mix_buffer_length);
ags_linear_interpolate_util_set_format(linear_interpolate_util,
AGS_SOUNDCARD_COMPLEX);
ags_linear_interpolate_util_set_factor(linear_interpolate_util,
freq_period / low_freq_period);
ags_linear_interpolate_util_pitch(linear_interpolate_util);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
double _Complex new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((start_x + (guint) floor(new_phase)) * source_stride);
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period)) * source_stride);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + ((guint) floor(new_phase) * source_stride);
}else{
ptr_mix_buffer = mix_buffer + ((buffer_length - 1) * source_stride);
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0].real != 0.0){
new_z = volume * ((new_freq_period * (ags_complex_get(ptr_mix_buffer) / freq_period) * (ags_complex_get(ptr_low_mix_buffer) / low_freq_period) / (ags_complex_get(ptr_mix_buffer) / freq_period)));
}else{
new_z = 0;
}
ags_complex_set(ptr_new_mix_buffer,
new_z);
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
ags_complex_set(destination + (i * destination_stride),
ags_complex_get(new_mix_buffer + i));
}
}
/**
* ags_hq_pitch_util_pitch:
* @hq_pitch_util: the #AgsHQPitchUtil-struct
*
* Pitch @hq_pitch_util.
*
* Since: 3.9.6
*/
void
ags_hq_pitch_util_pitch(AgsHQPitchUtil *hq_pitch_util)
{
if(hq_pitch_util == NULL ||
hq_pitch_util->destination == NULL ||
hq_pitch_util->source == NULL){
return;
}
switch(hq_pitch_util->format){
case AGS_SOUNDCARD_SIGNED_8_BIT:
{
ags_hq_pitch_util_pitch_s8(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_SIGNED_16_BIT:
{
ags_hq_pitch_util_pitch_s16(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_SIGNED_24_BIT:
{
ags_hq_pitch_util_pitch_s24(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_SIGNED_32_BIT:
{
ags_hq_pitch_util_pitch_s32(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_SIGNED_64_BIT:
{
ags_hq_pitch_util_pitch_s64(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_FLOAT:
{
ags_hq_pitch_util_pitch_float(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_DOUBLE:
{
ags_hq_pitch_util_pitch_double(hq_pitch_util);
}
break;
case AGS_SOUNDCARD_COMPLEX:
{
ags_hq_pitch_util_pitch_complex(hq_pitch_util);
}
break;
default:
g_warning("unknown format");
}
}
/**
* ags_hq_pitch_util_compute_s8:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_s8(gint8 *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gint8 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint8 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = 2.0 * M_PI * samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gint8 *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_SIGNED_8_BIT);
new_mix_buffer = (gint8 *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_SIGNED_8_BIT);
ags_linear_interpolate_util_fill_s8(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint8 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_s16:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_s16(gint16 *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gint16 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint16 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gint16 *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_SIGNED_16_BIT);
new_mix_buffer = (gint16 *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_SIGNED_16_BIT);
ags_linear_interpolate_util_fill_s16(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint16 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_s24:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_s24(gint32 *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gint32 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint32 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gint32 *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_SIGNED_24_BIT);
new_mix_buffer = (gint32 *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_SIGNED_24_BIT);
ags_linear_interpolate_util_fill_s24(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint32 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_s32:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_s32(gint32 *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gint32 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint32 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gint32 *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_SIGNED_32_BIT);
new_mix_buffer = (gint32 *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_SIGNED_32_BIT);
ags_linear_interpolate_util_fill_s32(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint32 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_s64:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_s64(gint64 *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gint64 *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gint64 *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gint64 *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_SIGNED_64_BIT);
new_mix_buffer = (gint64 *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_SIGNED_64_BIT);
ags_linear_interpolate_util_fill_s64(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gint64 new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_float:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_float(gfloat *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gfloat *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gfloat *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gfloat *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_FLOAT);
new_mix_buffer = (gfloat *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_FLOAT);
ags_linear_interpolate_util_fill_float(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gfloat new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_double:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_double(gdouble *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
gdouble *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
gdouble *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (gdouble *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_DOUBLE);
new_mix_buffer = (gdouble *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_DOUBLE);
ags_linear_interpolate_util_fill_double(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
gdouble new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ptr_mix_buffer[0] != 0){
new_z = volume * ((new_freq_period * (ptr_mix_buffer[0] / freq_period) * (ptr_low_mix_buffer[0] / low_freq_period) / (ptr_mix_buffer[0] / freq_period)));
}else{
new_z = 0;
}
ptr_new_mix_buffer[0] = new_z;
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
buffer[i] = new_mix_buffer[i];
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}
/**
* ags_hq_pitch_util_compute_complex:
* @buffer: the audio buffer
* @buffer_length: the audio buffer's length
* @samplerate: the samplerate
* @base_key: the base key
* @tuning: the tuning
*
* Apply pitch filter.
*
* Since: 3.8.0
*/
void
ags_hq_pitch_util_compute_complex(AgsComplex *buffer,
guint buffer_length,
guint samplerate,
gdouble base_key,
gdouble tuning)
{
AgsComplex *ptr_mix_buffer, *ptr_low_mix_buffer, *ptr_new_mix_buffer;
AgsComplex *mix_buffer, *new_mix_buffer, *low_mix_buffer;
gdouble volume;
gdouble base_freq, low_freq, new_freq;
gdouble offset_factor, low_offset_factor, new_offset_factor;
gdouble freq_period, low_freq_period, new_freq_period;
guint low_mix_buffer_length;
guint i, j;
if(buffer == NULL ||
buffer_length == 0){
return;
}
/* frequency */
base_freq = exp2((base_key) / 12.0) * 440.0;
new_freq = exp2((base_key + (tuning / 100.0)) / 12.0) * 440.0;
low_freq = exp2((base_key - 0.25) / 12.0) * 440.0;
if(base_freq <= 0.0){
g_warning("rejecting pitch base freq %f <= 0.0", base_freq);
return;
}
if(low_freq <= 0.0){
g_warning("rejecting pitch low freq %f <= 0.0", low_freq);
return;
}
if(new_freq <= 0.0){
g_warning("rejecting pitch new freq %f <= 0.0", new_freq);
return;
}
if(tuning == 0.0){
return;
}
volume = 1.0 / base_freq * new_freq;
/* get frequency period */
freq_period = samplerate / base_freq;
low_freq_period = samplerate / low_freq;
new_freq_period = samplerate / new_freq;
/* get offset factor */
offset_factor = 1.0;
low_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / low_freq);
new_offset_factor = 1.0 / (samplerate / base_freq) * (samplerate / new_freq);
/* allocate buffer */
mix_buffer = buffer;
low_mix_buffer_length = (freq_period / low_freq_period) * buffer_length;
low_mix_buffer = (AgsComplex *) ags_stream_alloc(low_mix_buffer_length,
AGS_SOUNDCARD_COMPLEX);
new_mix_buffer = (AgsComplex *) ags_stream_alloc(buffer_length,
AGS_SOUNDCARD_COMPLEX);
ags_linear_interpolate_util_fill_complex(low_mix_buffer,
buffer,
low_mix_buffer_length,
freq_period / low_freq_period);
/* new mix buffer */
for(i = 0, j = 0; i < buffer_length; i++, j++){
double _Complex new_z;
gdouble phase, low_phase, new_phase;
guint start_x, low_start_x;
if(j >= new_freq_period){
j = 0;
}
if(floor(freq_period) != 0.0){
start_x = freq_period * floor((double) i / freq_period);
}else{
start_x = 0;
}
if(floor(low_freq_period) != 0.0){
low_start_x = low_freq_period * floor((double) i / low_freq_period);
}else{
low_start_x = 0;
}
phase = fmod(i, freq_period);
low_phase = fmod(i, low_freq_period);
new_phase = fmod(i, new_freq_period);
if(start_x + (guint) floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase));
}else{
if((start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) < buffer_length &&
(start_x + (guint) floor(new_phase)) - (guint) floor(freq_period) > 0){
ptr_mix_buffer = mix_buffer + (start_x + (guint) floor(new_phase)) - (guint) floor(freq_period);
}else{
if(floor(new_phase) < buffer_length){
ptr_mix_buffer = mix_buffer + (guint) floor(new_phase);
}else{
ptr_mix_buffer = mix_buffer + buffer_length - 1;
}
}
}
if(low_start_x + (guint) floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase));
}else{
if((low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) < low_mix_buffer_length &&
(low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period) > 0){
ptr_low_mix_buffer = low_mix_buffer + (low_start_x + (guint) floor(new_phase)) - (guint) floor(low_freq_period);
}else{
if(floor(new_phase) < low_mix_buffer_length){
ptr_low_mix_buffer = low_mix_buffer + (guint) floor(new_phase);
}else{
ptr_low_mix_buffer = low_mix_buffer + low_mix_buffer_length - 1;
}
}
}
ptr_new_mix_buffer = new_mix_buffer + i;
/* write new mix buffer */
if(ags_complex_get(ptr_mix_buffer) != 0.0 &&
ags_complex_get(ptr_mix_buffer) != I * 0.0){
new_z = volume * ((new_freq_period * (ags_complex_get(ptr_mix_buffer) / freq_period) * (ags_complex_get(ptr_low_mix_buffer) / low_freq_period) / (ags_complex_get(ptr_mix_buffer) / freq_period)));
}else{
new_z = 0;
}
ags_complex_set(ptr_new_mix_buffer,
new_z);
}
/* rewrite buffer */
for(i = 0; i < buffer_length; i++){
ags_complex_set(buffer + i,
ags_complex_get(new_mix_buffer + i));
}
ags_stream_free(low_mix_buffer);
ags_stream_free(new_mix_buffer);
}