2005-04-17 02:20:36 +04:00
/*
2007-10-15 11:50:19 +04:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-17 02:20:36 +04:00
*
*
* 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 ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/time.h>
# include <sound/core.h>
# include <sound/gus.h>
# define __GUS_TABLES_ALLOC__
# include "gus_tables.h"
EXPORT_SYMBOL ( snd_gf1_atten_table ) ; /* for snd-gus-synth module */
unsigned short snd_gf1_lvol_to_gvol_raw ( unsigned int vol )
{
unsigned short e , m , tmp ;
if ( vol > 65535 )
vol = 65535 ;
tmp = vol ;
e = 7 ;
if ( tmp < 128 ) {
while ( e > 0 & & tmp < ( 1 < < e ) )
e - - ;
} else {
while ( tmp > 255 ) {
tmp > > = 1 ;
e + + ;
}
}
m = vol - ( 1 < < e ) ;
if ( m > 0 ) {
if ( e > 8 )
m > > = e - 8 ;
else if ( e < 8 )
m < < = 8 - e ;
m & = 255 ;
}
return ( e < < 8 ) | m ;
}
2005-05-23 12:29:53 +04:00
#if 0
2005-04-17 02:20:36 +04:00
unsigned int snd_gf1_gvol_to_lvol_raw ( unsigned short gf1_vol )
{
unsigned int rvol ;
unsigned short e , m ;
if ( ! gf1_vol )
return 0 ;
e = gf1_vol > > 8 ;
m = ( unsigned char ) gf1_vol ;
rvol = 1 < < e ;
if ( e > 8 )
return rvol | ( m < < ( e - 8 ) ) ;
return rvol | ( m > > ( 8 - e ) ) ;
}
2005-11-17 16:36:44 +03:00
unsigned int snd_gf1_calc_ramp_rate ( struct snd_gus_card * gus ,
2005-04-17 02:20:36 +04:00
unsigned short start ,
unsigned short end ,
unsigned int us )
{
static unsigned char vol_rates [ 19 ] =
{
23 , 24 , 26 , 28 , 29 , 31 , 32 , 34 ,
36 , 37 , 39 , 40 , 42 , 44 , 45 , 47 ,
49 , 50 , 52
} ;
unsigned short range , increment , value , i ;
start > > = 4 ;
end > > = 4 ;
if ( start < end )
us / = end - start ;
else
us / = start - end ;
range = 4 ;
value = gus - > gf1 . enh_mode ?
vol_rates [ 0 ] :
vol_rates [ gus - > gf1 . active_voices - 14 ] ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( us < value ) {
range = i ;
break ;
} else
value < < = 3 ;
}
if ( range = = 4 ) {
range = 3 ;
increment = 1 ;
} else
increment = ( value + ( value > > 1 ) ) / us ;
return ( range < < 6 ) | ( increment & 0x3f ) ;
}
2005-05-23 12:29:53 +04:00
# endif /* 0 */
2005-11-17 16:36:44 +03:00
unsigned short snd_gf1_translate_freq ( struct snd_gus_card * gus , unsigned int freq16 )
2005-04-17 02:20:36 +04:00
{
freq16 > > = 3 ;
if ( freq16 < 50 )
freq16 = 50 ;
if ( freq16 & 0xf8000000 ) {
freq16 = ~ 0xf8000000 ;
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " snd_gf1_translate_freq: overflow - freq = 0x%x \n " , freq16 ) ;
2005-04-17 02:20:36 +04:00
}
return ( ( freq16 < < 9 ) + ( gus - > gf1 . playback_freq > > 1 ) ) / gus - > gf1 . playback_freq ;
}
2005-05-23 12:29:53 +04:00
#if 0
2005-04-17 02:20:36 +04:00
short snd_gf1_compute_vibrato ( short cents , unsigned short fc_register )
{
static short vibrato_table [ ] =
{
0 , 0 , 32 , 592 , 61 , 1175 , 93 , 1808 ,
124 , 2433 , 152 , 3007 , 182 , 3632 , 213 , 4290 ,
241 , 4834 , 255 , 5200
} ;
long depth ;
short * vi1 , * vi2 , pcents , v1 ;
pcents = cents < 0 ? - cents : cents ;
for ( vi1 = vibrato_table , vi2 = vi1 + 2 ; pcents > * vi2 ; vi1 = vi2 , vi2 + = 2 ) ;
v1 = * ( vi1 + 1 ) ;
/* The FC table above is a list of pairs. The first number in the pair */
/* is the cents index from 0-255 cents, and the second number in the */
/* pair is the FC adjustment needed to change the pitch by the indexed */
/* number of cents. The table was created for an FC of 32768. */
/* The following expression does a linear interpolation against the */
/* approximated log curve in the table above, and then scales the number */
/* by the FC before the LFO. This calculation also adjusts the output */
/* value to produce the appropriate depth for the hardware. The depth */
/* is 2 * desired FC + 1. */
depth = ( ( ( int ) ( * ( vi2 + 1 ) - * vi1 ) * ( pcents - * vi1 ) / ( * vi2 - * vi1 ) ) + v1 ) * fc_register > > 14 ;
if ( depth )
depth + + ;
if ( depth > 255 )
depth = 255 ;
return cents < 0 ? - ( short ) depth : ( short ) depth ;
}
unsigned short snd_gf1_compute_pitchbend ( unsigned short pitchbend , unsigned short sens )
{
static long log_table [ ] = { 1024 , 1085 , 1149 , 1218 , 1290 , 1367 , 1448 , 1534 , 1625 , 1722 , 1825 , 1933 } ;
int wheel , sensitivity ;
unsigned int mantissa , f1 , f2 ;
unsigned short semitones , f1_index , f2_index , f1_power , f2_power ;
char bend_down = 0 ;
int bend ;
if ( ! sens )
return 1024 ;
wheel = ( int ) pitchbend - 8192 ;
sensitivity = ( ( int ) sens * wheel ) / 128 ;
if ( sensitivity < 0 ) {
bend_down = 1 ;
sensitivity = - sensitivity ;
}
semitones = ( unsigned int ) ( sensitivity > > 13 ) ;
mantissa = sensitivity % 8192 ;
f1_index = semitones % 12 ;
f2_index = ( semitones + 1 ) % 12 ;
f1_power = semitones / 12 ;
f2_power = ( semitones + 1 ) / 12 ;
f1 = log_table [ f1_index ] < < f1_power ;
f2 = log_table [ f2_index ] < < f2_power ;
bend = ( int ) ( ( ( ( f2 - f1 ) * mantissa ) > > 13 ) + f1 ) ;
if ( bend_down )
bend = 1048576L / bend ;
return bend ;
}
unsigned short snd_gf1_compute_freq ( unsigned int freq ,
unsigned int rate ,
unsigned short mix_rate )
{
unsigned int fc ;
int scale = 0 ;
while ( freq > = 4194304L ) {
scale + + ;
freq > > = 1 ;
}
fc = ( freq < < 10 ) / rate ;
if ( fc > 97391L ) {
fc = 97391 ;
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " patch: (1) fc frequency overflow - %u \n " , fc ) ;
2005-04-17 02:20:36 +04:00
}
fc = ( fc * 44100UL ) / mix_rate ;
while ( scale - - )
fc < < = 1 ;
if ( fc > 65535L ) {
fc = 65535 ;
2005-10-20 20:26:44 +04:00
snd_printk ( KERN_ERR " patch: (2) fc frequency overflow - %u \n " , fc ) ;
2005-04-17 02:20:36 +04:00
}
return ( unsigned short ) fc ;
}
2005-05-23 12:29:53 +04:00
# endif /* 0 */