Major update to TimeScale effect, incorporating libsbsms-2.0.0, fixes to bug 172, changes to ui

This commit is contained in:
clayton.otey 2011-07-02 18:35:18 +00:00
parent 9869ea4afd
commit a17e741abc
45 changed files with 12912 additions and 6785 deletions

View File

@ -1,196 +0,0 @@
Version 2.0.2 (15 Aug 2005)
* packaging changes:
- require automake (>= 1.5) for 'make -f Makefile.cvs'
(mandatory for 'dist-bzip2' automake option)
* src/gig.cpp, src/gig.h:
- support for gig v3 multi-file format (.gig, .gx01, .gx02, ...),
the extension files are read automatically when the samples are
loaded
- fixed the 24 bit decompression, the result should now be exact
instead of an approximation
- added VCFCutoffControllerInvert parameter and GetVelocityCutoff
function to DimensionRegion
* src/DLS.cpp, src/DLS.h:
- the upper bits of the pool table indices are read (used as
extension file numbers for gig v3)
* src/RIFF.cpp, src/RIFF.h:
- the file name is remembered in the RIFF::File object
Version 2.0.1 (12 Jun 2005)
* packaging changes:
- include debian/ directory on 'make dist'
- create a bzip2 tarball on 'make dist'
* src/gigextract.cpp:
- show also version of libsndfile or build version of libaudiofile when
using the -v switch
- fixed mutual link dependency to libsndfile / libaudiofile
* src/gig.cpp, src/gig.h:
- added DimensionRegion::GetVelocityRelease function
Version 2.0.0 (9 May 2005)
* packaging changes:
- fixed conditional linkage of either libsndfile or libaudiofile
(if none of the two exist, configure script will abort)
- man pages are now auto generated with the correct libgig version
* src/gig.cpp, src/gig.h:
- experimental support for Gigasampler v3 format;
64 bit file offsets are truncated to 32 bit, 24 bit samples are
truncated to 16 bit, up to 8 dimensions are read, additional
articulation informations are ignored at the moment
(patch by Andreas Persson)
- added some file format compatibility checks
- fixed vcf_type_lowpassturbo value (vcf_type_lowpassturbo was actually
never used, because the necessary check was made before
initialization)
- fixed crossfade points order (structure for big endian and little
endian systems was interchanged)
- fixed some memory leaks (patch by 'Gene', a.k.a Anders Alm)
- fixed crash which occured when patches did not have a sample assigned
to their region or dimension region (patch by Andreas Persson)
- support for compressed mono samples
- experimental support for compressed 24 bit samples
- fixed decompression on big-endian CPUs
- fixed decompression bug that truncated the last block of samples
- external decompression buffers can now be used for streaming samples
to avoid race conditions in case of multiple streaming threads
- added pre-calculated sample attenuation parameter
- added v3 "random" and "round robin" dimensions
- implemented progress indicator callback mechanism for loading
instruments and samples
- added functions libraryName() and libraryVersion()
* src/DLS.cpp, src/DLS.h:
- fixed File constructor which caused variable File::Instruments always
to be zero
- added functions libraryName() and libraryVersion()
* src/RIFF.cpp, src/RIFF.h:
- fixed method List::LoadSubChunks() which did not restore the original
position within the body of the given list chunk
- added functions libraryName() and libraryVersion()
* src/rifftree.cpp:
- added command line switch -v to show rifftree's revision and the used
libgig version
* src/dlsdump.cpp:
- added command line switch -v to show dlsdump's revision and the used
libgig version
* src/gigdump.cpp:
- added output of UnityNote, FineTune, Gain, SampleStartOffset an
LoopPlayCount
- added command line switch -v to show gigdump's revision and the used
libgig version
* src/gigextract.cpp:
- support for compressed mono samples and compressed 24 bit samples
- added command line switch -v to show gigextract's revision and the
used libgig version
Version 1.0.0 (26 Nov 2004)
* packaging changes:
- renamed 'libgig.pc.in' -> 'gig.pc.in' and renamed pkg-config lib name
'libgig' -> 'gig' as it's common practice to omit the 'lib' prefix
- fixed man pages automake install rule (which didn't work on Mandrake,
SuSE and Fedora)
- fixed generation of Doxygen API documentation (now also included in
RPM and Debian packages)
* src/gig.cpp, src/gig.h:
- fixed / improved accuracy of all three velocity to volume
transformation functions a.k.a. 'nonlinear','linear','special'
(patch by Andreas Persson)
- denormals are filtered from the velocity to volume tables
- bugfix for dimension region switching (wrong handling of the release
trigger dimension, no bit range check for dimensions of split type
'split_type_bit')
- fixed panorama value in DimensionRegion (invalid conversion from
signed 7 bit to signed 8 bit)
- added class attribute 'Layers' to class 'gig::Region'
- symbol prototyping of gig::Region (fixes build failure with qsampler)
* src/gigextract.cpp:
- added support for libsndfile (if libaudiofile and libsndfile are
available then libsndfile is preferred)
* src/gigdump.cpp:
- added printout for dimension informations (amount, type, bits, zones)
- added printout for velocity response curve parameters
- added printout for crossfade definitions
- added printout for panorama value for each DimensionRegion
- replaced printout of DLS Region layer by printout of amount of
Gigasampler layers
Version 0.7.1 (2 Jul 2004)
* packaging changes:
- added libgig.spec and libgig.pc package configurations for generating
Redhat packages
- header files included on installation.
- autotools-generated files removed from CVS repository.
- added support for generating Debian packages
- version of shared library can be set in configure.in
Version 0.7.0 (3 May 2004)
* general changes:
- various big endian specific corrections
(successfully tested now on PPC)
- minor adjustments to avoid compile errors on some systems
(using now pow() instead of powl() and --pedantic g++ compiler switch)
- libtoolized the library
- added man pages for the command line tools
(gigextract, gigdump, dlsdump, rifftree)
* src/gig.cpp, src/gig.h:
- fixed bug in decompression algorithm which caused it not to detect
the end of a stream
- added method GetVelocityAttenuation() to class 'DimensionRegion' which
takes the MIDI key velocity value as an argument and returns the
appropriate volume factor (0.0 ... 1.0) for the sample to be played
back, the velocity curve transformation functions used for this are
only an approximation so far
- fixed class attributes 'Sample::LoopStart', 'Sample::LoopEnd' and
'Sample::LoopSize' which reflected wrong values
- class attributes 'Sample::LoopStart' and 'Sample::LoopEnd' are now
measured in sample points instead of byte offset
- renamed misleading attribute name 'Sample::MIDIPitchFraction' to
'Sample::FineTune'
- added class attribute 'Sample::LoopSize'
- added method GetInstrument(uint index) to class 'File'
- added ReadAndLoop() method to class 'Sample' which is an extension to
the normal Read() method to honor the sample's looping information
while streaming from disk
- changed interface for 'attenuation_ctrl_t', 'eg1_ctrl_t' and
'eg2_ctrl_t': replaced this huge enumeration by a structure which
reflects the MIDI controller number in case of an ordinary control
change controller (this saves a huge switch-case block in the
application of the library user)
- renamed following attributes in class 'DimensionRegion':
'AttenuationContol' -> 'AttenuationController',
'InvertAttenuationControl' -> 'InvertAttenuationController',
'AttenuationControlTreshold' -> 'AttenuationControllerThreshold'
- minor fix in API documentation for method GetVelocityAttenuation() in
class 'DimensionRegion'
* src/RIFF.cpp, src/RIFF.h:
- added additional API documentation
- minor fix in Chunk::Read() method (only a minor efficiency issue)
* src/gigdump.cpp:
- added printout of samples' looping informations
Version 0.6.0 (3 Nov 2003)
* initial release

View File

@ -42,6 +42,8 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
$(top_srcdir)/m4/ac_c99_func_lrintf.m4 \
$(top_srcdir)/m4/ax_check_compiler_flags.m4 \
$(top_srcdir)/m4/ax_compiler_vendor.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.in

View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for sbsms 1.5.0.
# Generated by GNU Autoconf 2.61 for sbsms 2.0.0.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
@ -721,8 +721,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='sbsms'
PACKAGE_TARNAME='sbsms'
PACKAGE_VERSION='1.5.0'
PACKAGE_STRING='sbsms 1.5.0'
PACKAGE_VERSION='2.0.0'
PACKAGE_STRING='sbsms 2.0.0'
PACKAGE_BUGREPORT=''
ac_unique_file="src/sbsms.cpp"
@ -1400,7 +1400,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sbsms 1.5.0 to adapt to many kinds of systems.
\`configure' configures sbsms 2.0.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1471,7 +1471,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sbsms 1.5.0:";;
short | recursive ) echo "Configuration of sbsms 2.0.0:";;
esac
cat <<\_ACEOF
@ -1483,9 +1483,11 @@ Optional Features:
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-universal_binary enable universal binary build: (default: disable)
--enable-static enable static build: (default: disable)
--enable-debug enable debug build: (default: disable)
--enable-multithreaded enable multithreaded build: (default: disable)
--enable-sse enable SSE optimizations
--enable-universal_binary enable universal binary build: (default: disable)
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
--enable-maintainer-mode enable make rules and dependencies not useful
@ -1574,7 +1576,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sbsms configure 1.5.0
sbsms configure 2.0.0
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@ -1588,7 +1590,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sbsms $as_me 1.5.0, which was
It was created by sbsms $as_me 2.0.0, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@ -1947,8 +1949,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
#------------------------------------------------------------------------------------
# Library's "official" release version:
LIBSBSMS_RELEASE_MAJOR=1
LIBSBSMS_RELEASE_MINOR=7
LIBSBSMS_RELEASE_MAJOR=2
LIBSBSMS_RELEASE_MINOR=0
LIBSBSMS_RELEASE_BUILD=0
ac_aux_dir=
@ -2159,7 +2161,7 @@ fi
# 6. If any interfaces have been removed since the last public release, then set age
# to 0.
SHARED_VERSION_INFO="8:0:7"
SHARED_VERSION_INFO="10:0:0"
case `pwd` in
*\ * | *\ *)
@ -3758,13 +3760,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3761: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3763: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3764: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3766: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3767: output\"" >&5)
(eval echo "\"\$as_me:3769: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@ -4986,7 +4988,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 4989 "configure"' > conftest.$ac_ext
echo '#line 4991 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@ -6102,7 +6104,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
else
ac_cv_header_stdc=no
fi
rm -f conftest*
rm -f -r conftest*
fi
@ -6123,7 +6125,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
else
ac_cv_header_stdc=no
fi
rm -f conftest*
rm -f -r conftest*
fi
@ -6807,11 +6809,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6810: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6812: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6814: \$? = $ac_status" >&5
echo "$as_me:6816: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -7146,11 +7148,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7149: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7151: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7153: \$? = $ac_status" >&5
echo "$as_me:7155: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -7251,11 +7253,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7254: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7256: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7258: \$? = $ac_status" >&5
echo "$as_me:7260: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -7306,11 +7308,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7309: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7311: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7313: \$? = $ac_status" >&5
echo "$as_me:7315: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -10075,7 +10077,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 10078 "configure"
#line 10080 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -10171,7 +10173,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 10174 "configure"
#line 10176 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -13176,11 +13178,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:13179: $lt_compile\"" >&5)
(eval echo "\"\$as_me:13181: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:13183: \$? = $ac_status" >&5
echo "$as_me:13185: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@ -13275,11 +13277,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:13278: $lt_compile\"" >&5)
(eval echo "\"\$as_me:13280: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:13282: \$? = $ac_status" >&5
echo "$as_me:13284: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -13327,11 +13329,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:13330: $lt_compile\"" >&5)
(eval echo "\"\$as_me:13332: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:13334: \$? = $ac_status" >&5
echo "$as_me:13336: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@ -14527,281 +14529,72 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
{ echo "$as_me:$LINENO: checking for C++ compiler vendor" >&5
echo $ECHO_N "checking for C++ compiler vendor... $ECHO_C" >&6; }
if test "${ax_cv_cxx_compiler_vendor+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ax_cv_cxx_compiler_vendor=unknown
# note: don't check for gcc first since some other compilers define __GNUC__
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
main ()
{
#if !($vencpp)
thisisanerror;
#endif
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
ax_cv_cxx_compiler_vendor=`echo $ventest | cut -d: -f1`; break
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
fi
{ echo "$as_me:$LINENO: result: $ax_cv_cxx_compiler_vendor" >&5
echo "${ECHO_T}$ax_cv_cxx_compiler_vendor" >&6; }
# restore those variables back
CFLAGS="$cflags_save"
CPPFLAGS="$cppflags_save"
CXXFLAGS="$cxxflags_save"
for ac_func in malloc calloc free memcpy memmove
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5
echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define $ac_func innocuous_$ac_func
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef $ac_func
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char $ac_func ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_$ac_func || defined __stub___$ac_func
choke me
#endif
int
main ()
{
return $ac_func ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
eval "$as_ac_var=yes"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
eval "$as_ac_var=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
ac_res=`eval echo '${'$as_ac_var'}'`
{ echo "$as_me:$LINENO: result: $ac_res" >&5
echo "${ECHO_T}$ac_res" >&6; }
if test `eval echo '${'$as_ac_var'}'` = yes; then
cat >>confdefs.h <<_ACEOF
#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi
done
{ echo "$as_me:$LINENO: checking for floor in -lm" >&5
echo $ECHO_N "checking for floor in -lm... $ECHO_C" >&6; }
if test "${ac_cv_lib_m_floor+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lm $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char floor ();
int
main ()
{
return floor ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
ac_cv_lib_m_floor=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_m_floor=no
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ echo "$as_me:$LINENO: result: $ac_cv_lib_m_floor" >&5
echo "${ECHO_T}$ac_cv_lib_m_floor" >&6; }
if test $ac_cv_lib_m_floor = yes; then
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBM 1
_ACEOF
LIBS="-lm $LIBS"
fi
for ac_func in floor sqrt log exp sin cos
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5
echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define $ac_func innocuous_$ac_func
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef $ac_func
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char $ac_func ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_$ac_func || defined __stub___$ac_func
choke me
#endif
int
main ()
{
return $ac_func ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
eval "$as_ac_var=yes"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
eval "$as_ac_var=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
ac_res=`eval echo '${'$as_ac_var'}'`
{ echo "$as_me:$LINENO: result: $ac_res" >&5
echo "${ECHO_T}$ac_res" >&6; }
if test `eval echo '${'$as_ac_var'}'` = yes; then
cat >>confdefs.h <<_ACEOF
#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi
done
{ echo "$as_me:$LINENO: checking for lrint" >&5
echo $ECHO_N "checking for lrint... $ECHO_C" >&6; }
if test "${ac_cv_c99_lrint+set}" = set; then
@ -14930,14 +14723,6 @@ fi
# Check whether --enable-universal_binary was given.
if test "${enable_universal_binary+set}" = set; then
enableval=$enable_universal_binary; enable_universal_binary=$enableval
else
enable_universal_binary=no
fi
# Check whether --enable-static was given.
if test "${enable_static+set}" = set; then
enableval=$enable_static; enable_static=$enableval
@ -14954,7 +14739,31 @@ else
fi
SBSMS_CFLAGS="-ffast-math -fstrict-aliasing"
# Check whether --enable-multithreaded was given.
if test "${enable_multithreaded+set}" = set; then
enableval=$enable_multithreaded; enable_multithreaded=$enableval
else
enable_multithreaded=no
fi
# Check whether --enable-sse was given.
if test "${enable_sse+set}" = set; then
enableval=$enable_sse; enable_sse=$enableval
else
enable_sse=yes
fi
# Check whether --enable-universal_binary was given.
if test "${enable_universal_binary+set}" = set; then
enableval=$enable_universal_binary; enable_universal_binary=$enableval
else
enable_universal_binary=no
fi
SBSMS_CFLAGS="-ffast-math -funroll-loops"
if test x$enable_static = xno; then
case "$target_os" in
@ -14966,6 +14775,141 @@ if test x$enable_static = xno; then
esac
fi
if test x$enable_debug = xyes; then
SBSMS_CFLAGS="$SBSMS_CFLAGS -g -O3"
else
SBSMS_CFLAGS="$SBSMS_CFLAGS -O3 -fomit-frame-pointer"
fi
if test x$enable_multithreaded = xyes; then
cat >>confdefs.h <<\_ACEOF
#define MULTITHREADED 1
_ACEOF
fi
echo "${ax_cv_cxx_compiler_vendor} XXX"
if test x$enable_sse = xyes; then
if test "${ax_cv_cxx_compiler_vendor}" = "gnu"; then
{ echo "$as_me:$LINENO: checking whether C++ compiler accepts -msse" >&5
echo $ECHO_N "checking whether C++ compiler accepts -msse... $ECHO_C" >&6; }
if test "${ax_cv_cxx_flags__msse+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ax_save_FLAGS=$CXXFLAGS
CXXFLAGS="-msse"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
ax_cv_cxx_flags__msse=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ax_cv_cxx_flags__msse=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CXXFLAGS=$ax_save_FLAGS
fi
eval ax_check_compiler_flags=$ax_cv_cxx_flags__msse
{ echo "$as_me:$LINENO: result: $ax_check_compiler_flags" >&5
echo "${ECHO_T}$ax_check_compiler_flags" >&6; }
if test "x$ax_check_compiler_flags" = xyes; then
SBSMS_CFLAGS="$SBSMS_CFLAGS -msse"
else
{ { echo "$as_me:$LINENO: error: Need a version of gcc with -msse" >&5
echo "$as_me: error: Need a version of gcc with -msse" >&2;}
{ (exit 1); exit 1; }; }
fi
fi
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <xmmintrin.h>
int
main ()
{
__m128 v,w; float p[8]; v = _mm_loadu_ps(p); _mm_storeu_ps(p,v); w = _mm_loadl_pi(w,(const __m64*)p); w = _mm_loadh_pi(w,(const __m64*)p); _mm_storel_pi((__m64 *)p, w); _mm_storeh_pi((__m64 *)p, w); v = _mm_add_ps(v,w); v = _mm_sub_ps(v,w); v = _mm_mul_ps(v,w); v = _mm_shuffle_ps(v,w,_MM_SHUFFLE(0,1,2,3)); w = _mm_set1_ps(0.0f);
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
sse_ok=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
sse_ok=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test x$sse_ok = xyes; then
cat >>confdefs.h <<\_ACEOF
#define ENABLE_SSE 1
_ACEOF
fi
fi
if test x$enable_universal_binary = xyes; then
case "$target_os" in
darwin*)
@ -14976,20 +14920,6 @@ if test x$enable_universal_binary = xyes; then
esac
fi
case "$target_os" in
darwin*)
macosx="yes"
;;
*)
macosx="no"
;;
esac
if test x$enable_debug = xyes; then
SBSMS_CFLAGS="$SBSMS_CFLAGS -g"
else
SBSMS_CFLAGS="$SBSMS_CFLAGS -O3"
fi
am__api_version='1.10'
@ -15360,7 +15290,7 @@ fi
# Define the identity of the package.
PACKAGE='sbsms'
VERSION='1.5.0'
VERSION='2.0.0'
cat >>confdefs.h <<_ACEOF
@ -16172,7 +16102,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sbsms $as_me 1.5.0, which was
This file was extended by sbsms $as_me 2.0.0, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -16225,7 +16155,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
sbsms config.status 1.5.0
sbsms config.status 2.0.0
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -1,4 +1,4 @@
AC_INIT([sbsms],[1.5.0])
AC_INIT([sbsms],[2.0.0])
dnl Use the m4/ directory to contain libtool macros that will be needed to
dnl go with the ltmain.sh script (both will be created/updated via the command
@ -8,8 +8,8 @@ AC_CONFIG_MACRO_DIR([m4])
#------------------------------------------------------------------------------------
# Library's "official" release version:
LIBSBSMS_RELEASE_MAJOR=1
LIBSBSMS_RELEASE_MINOR=7
LIBSBSMS_RELEASE_MAJOR=2
LIBSBSMS_RELEASE_MINOR=0
LIBSBSMS_RELEASE_BUILD=0
AC_CONFIG_SRCDIR([src/sbsms.cpp])
AC_CANONICAL_TARGET([])
@ -34,7 +34,7 @@ AC_DISABLE_SHARED dnl allows for optimizations
# 6. If any interfaces have been removed since the last public release, then set age
# to 0.
SHARED_VERSION_INFO="8:0:7"
SHARED_VERSION_INFO="10:0:0"
AC_PROG_LIBTOOL
AM_PROG_LIBTOOL
@ -47,29 +47,29 @@ cxxflags_save="$CXXFLAGS"
AC_LANG([C++])
AC_PROG_CXX
AC_PROG_CXXCPP
AX_COMPILER_VENDOR
# restore those variables back
CFLAGS="$cflags_save"
CPPFLAGS="$cppflags_save"
CXXFLAGS="$cxxflags_save"
AC_CHECK_FUNCS(malloc calloc free memcpy memmove)
AC_CHECK_LIB([m],floor)
AC_CHECK_FUNCS(floor sqrt log exp sin cos)
AC_C99_FUNC_LRINT()
AC_C99_FUNC_LRINTF()
AC_SUBST(SHLIB_VERSION_ARG)
AC_SUBST(SHARED_VERSION_INFO)
AC_ARG_ENABLE(universal_binary,[ --enable-universal_binary enable universal binary build: (default: disable)],[enable_universal_binary=$enableval],[enable_universal_binary=no])
AC_ARG_ENABLE(static,[ --enable-static enable static build: (default: disable)],[enable_static=$enableval],[enable_static=no])
AC_ARG_ENABLE(debug,[ --enable-debug enable debug build: (default: disable)],[enable_debug=$enableval],[enable_debug=no])
SBSMS_CFLAGS="-ffast-math -fstrict-aliasing"
AC_ARG_ENABLE(multithreaded,[ --enable-multithreaded enable multithreaded build: (default: disable)],[enable_multithreaded=$enableval],[enable_multithreaded=no])
AC_ARG_ENABLE(sse, [AC_HELP_STRING([--enable-sse],[enable SSE optimizations])], enable_sse=$enableval, enable_sse=yes)
AC_ARG_ENABLE(universal_binary,[ --enable-universal_binary enable universal binary build: (default: disable)],[enable_universal_binary=$enableval],[enable_universal_binary=no])
SBSMS_CFLAGS="-ffast-math -funroll-loops"
if test x$enable_static = xno; then
case "$target_os" in
@ -81,6 +81,31 @@ if test x$enable_static = xno; then
esac
fi
if test x$enable_debug = xyes; then
SBSMS_CFLAGS="$SBSMS_CFLAGS -g -O3"
else
SBSMS_CFLAGS="$SBSMS_CFLAGS -O3 -fomit-frame-pointer"
fi
if test x$enable_multithreaded = xyes; then
AC_DEFINE(MULTITHREADED,1,[Define to compile multithreaded sbsms])
fi
echo "${ax_cv_cxx_compiler_vendor} XXX"
if test x$enable_sse = xyes; then
if test "${ax_cv_cxx_compiler_vendor}" = "gnu"; then
AX_CHECK_COMPILER_FLAGS(-msse, [SBSMS_CFLAGS="$SBSMS_CFLAGS -msse"],[AC_MSG_ERROR([Need a version of gcc with -msse])])
fi
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <xmmintrin.h>]], [[__m128 v,w; float p[8]; v = _mm_loadu_ps(p); _mm_storeu_ps(p,v); w = _mm_loadl_pi(w,(const __m64*)p); w = _mm_loadh_pi(w,(const __m64*)p); _mm_storel_pi((__m64 *)p, w); _mm_storeh_pi((__m64 *)p, w); v = _mm_add_ps(v,w); v = _mm_sub_ps(v,w); v = _mm_mul_ps(v,w); v = _mm_shuffle_ps(v,w,_MM_SHUFFLE(0,1,2,3)); w = _mm_set1_ps(0.0f);]])], [sse_ok=yes], [sse_ok=no])
if test x$sse_ok = xyes; then
AC_DEFINE(ENABLE_SSE,1,[Define to enable sse])
fi
fi
if test x$enable_universal_binary = xyes; then
case "$target_os" in
darwin*)
@ -91,20 +116,6 @@ if test x$enable_universal_binary = xyes; then
esac
fi
case "$target_os" in
darwin*)
macosx="yes"
;;
*)
macosx="no"
;;
esac
if test x$enable_debug = xyes; then
SBSMS_CFLAGS="$SBSMS_CFLAGS -g"
else
SBSMS_CFLAGS="$SBSMS_CFLAGS -O3"
fi
AC_SUBST(SBSMS_CFLAGS)
AM_INIT_AUTOMAKE([])

View File

@ -1,172 +1,177 @@
// -*- mode: c++ -*-
#ifndef SBSMS_INCLUDE
#define SBSMS_INCLUDE
#include <stdio.h>
#define SBSMS_REAL_FLOAT 1
namespace _sbsms_ {
typedef float real;
typedef real interleaved[2];
typedef interleaved audio;
struct sbsms_quality {
long inframesize;
long maxoutframesize;
real minrate;
real maxrate;
int bands;
int M_MAX;
int H[5];
int N[8];
int S[8];
int res[8];
real pad[8];
real P[8];
real Q[8];
typedef float t_fft[2];
typedef t_fft audio;
typedef long long int SampleCountType;
typedef long long int TimeType;
typedef unsigned char TrackIndexType;
enum {
maxBands = 10,
numQualityParams = 52
};
extern const sbsms_quality sbsms_quality_standard;
extern const sbsms_quality sbsms_quality_fast;
struct SBSMSQualityParams {
int bands;
int H;
int N[maxBands];
int N0[maxBands];
int N1[maxBands];
int N2[maxBands];
int res[maxBands];
};
struct sbsms_resample_frame {
real ratio0;
real ratio1;
audio *in;
class SBSMSQuality {
public:
SBSMSQuality(const SBSMSQualityParams *params);
SBSMSQualityParams params;
long getFrameSize();
long getMaxPresamples();
};
extern const SBSMSQualityParams SBSMSQualityStandard;
struct SBSMSFrame {
float ratio0;
float ratio1;
audio *buf;
long size;
};
typedef long (*sbsms_cb)(audio *buf, long n, void *data);
typedef real (*sbsms_rate_cb)(long nProcessed, void *data);
typedef real (*sbsms_pitch_cb)(long nProcessed, void *data);
typedef long (*sbsms_resample_cb)(void *cb_data, sbsms_resample_frame *frame);
typedef long (*SBSMSResampleCB)(void *cbData, SBSMSFrame *frame);
class subband;
class TrackAllocator;
class PeakAllocator;
struct sbsms {
FILE *fp;
sbsms_cb getSamplesCB;
sbsms_rate_cb getRateCB;
sbsms_pitch_cb getPitchCB;
subband *top;
TrackAllocator *ta;
PeakAllocator *pa;
long n_prepad, n_postpad, n_prespent, n_processed;
bool bWritingComplete;
sbsms_quality quality;
int channels;
audio *ina;
void *threadData;
};
class SampleBufBase {
class SBSMSInterface {
public:
SampleBufBase() {};
virtual ~SampleBufBase() {};
virtual long read(audio *buf, long n)=0;
virtual void advance(long n)=0;
virtual long n_readable()=0;
virtual ~SBSMSInterface() {}
virtual long samples(audio *buf, long n) { return 0; }
virtual float getStretch(float t)=0;
virtual float getPitch(float t)=0;
virtual long getPresamples()=0;
virtual SampleCountType getSamplesToInput()=0;
virtual SampleCountType getSamplesToOutput()=0;
};
class grain;
class SampleBuf {
class SBSMSTrackPoint {
public:
//SampleBuf() {};
SampleBuf(int N);
SampleBuf(int N, long delay);
void init(int N, long delay);
void clear();
virtual ~SampleBuf();
void grow(long pos);
long write(audio *buf, long n);
long write(grain* g, int h);
virtual long read(audio *buf, long n);
virtual void advance(long n);
virtual long n_readable();
audio *getReadBuf();
long readPos, writePos;
long delay;
int N;
long length;
audio *buf;
virtual ~SBSMSTrackPoint() {}
virtual float getF()=0;
virtual float getM()=0;
virtual float getPhase()=0;
};
class SBSMSTrack {
public:
virtual ~SBSMSTrack() {}
virtual SBSMSTrackPoint *getSBSMSTrackPoint(const TimeType &time)=0;
virtual TrackIndexType getIndex()=0;
virtual bool isFirst(const TimeType &synthtime)=0;
virtual bool isLast(const TimeType &synthtime)=0;
};
class SBSMSRenderer {
public:
virtual ~SBSMSRenderer() {}
virtual void startFrame() {}
virtual void startTime(int c, const TimeType &time, int n) {}
virtual void render(int c, SBSMSTrack *t) {}
virtual void endTime(int c) {}
virtual void endFrame() {}
virtual void end(const SampleCountType &samples) {}
};
enum SBSMSError {
SBSMSErrorNone = 0,
SBSMSErrorInvalidRate
};
class SBSMSImp;
class SBSMS {
public:
SBSMS(int channels, SBSMSQuality *quality, bool bSynthesize);
~SBSMS();
long read(SBSMSInterface *iface, audio *buf, long n);
void addRenderer(SBSMSRenderer *renderer);
void removeRenderer(SBSMSRenderer *renderer);
long renderFrame(SBSMSInterface *iface);
long getInputFrameSize();
SBSMSError getError();
friend class SBSMSImp;
protected:
SBSMSImp *imp;
};
enum SlideType {
SlideIdentity = 0,
SlideConstant,
SlideLinearInputRate,
SlideLinearOutputRate,
SlideLinearInputStretch,
SlideLinearOutputStretch,
SlideGeometricInput,
SlideGeometricOutput
};
class SlideImp;
class Slide {
public:
Slide(SlideType slideType, float rate0 = 1.0f, float rate1 = 1.0f, const SampleCountType &n = 0);
~Slide();
float getTotalStretch();
float getStretchedTime(float t);
float getRate(float t);
float getStretch(float t);
float getRate();
float getStretch();
void step();
protected:
SlideImp *imp;
};
class SBSMSInterfaceSlidingImp;
class SBSMSInterfaceSliding : public SBSMSInterface {
public:
SBSMSInterfaceSliding(Slide *rateSlide,
Slide *pitchSlide,
bool bPitchReferenceInput,
const SampleCountType &samplesToInput,
long preSamples,
SBSMSQuality *quality);
virtual ~SBSMSInterfaceSliding();
virtual float getStretch(float t);
virtual float getPitch(float t);
virtual long getPresamples();
virtual SampleCountType getSamplesToInput();
virtual SampleCountType getSamplesToOutput();
friend class SBSMSInterfaceSlidingImp;
protected:
SBSMSInterfaceSlidingImp *imp;
};
class ResamplerImp;
class Resampler {
public:
Resampler(sbsms_resample_cb func, void *data);
Resampler(SampleBuf *in, real pitch);
Resampler(SBSMSResampleCB func, void *data, SlideType slideType = SlideConstant);
~Resampler();
long read(audio *audioOut, long frames);
void writingComplete();
void reset();
void init();
long samplesInOutput();
protected:
sbsms_resample_frame frame;
long startAbs;
long midAbs;
real midAbsf;
long endAbs;
long writePosAbs;
bool bInput;
SampleBuf *out;
sbsms_resample_cb cb;
void *data;
bool bPull;
SampleBuf *in;
long inOffset;
real sincZeros;
bool bWritingComplete;
ResamplerImp *imp;
};
void sbsms_init(int n);
void sbsms_reset(sbsms *sbsmser);
void sbsms_seek(sbsms *sbsmser, long framePos, long samplePos);
sbsms* sbsms_create(sbsms_cb getSamplesCB, sbsms_rate_cb getRateCB, sbsms_pitch_cb getPitchCB, int channels, sbsms_quality *quality, bool bPreAnalyze, bool bSynthesize);
sbsms* sbsms_create(FILE *fp, sbsms_rate_cb getRateCB, sbsms_pitch_cb getPitchCB);
void sbsms_destroy(sbsms* sbsmser);
long sbsms_read_frame(audio *out, void *data, sbsms *sbsmer, real *pitch0, real *pitch1);
long sbsms_write_frame(FILE *fp, void *data, sbsms *sbsmser);
long sbsms_samples_processed(sbsms *sbsmser);
long sbsms_pre_analyze(sbsms_cb getSamplesCB, void *data, sbsms *sbsmser);
void sbsms_pre_analyze_complete(sbsms *sbsmser);
long sbsms_get_samples_queued(sbsms *sbsmser);
long sbsms_get_frames_queued(sbsms *sbsmser);
long sbsms_get_last_input_frame_size(sbsms *sbsmser);
long sbsms_get_frame_pos(sbsms *sbsmser);
void sbsms_close_write(FILE *fp, sbsms *sbsmser);
FILE *sbsms_open_write(const char *fileName, sbsms *sbsmser, long samples_to_process);
void sbsms_close_read(FILE *fp);
FILE *sbsms_open_read(const char *fileName);
long sbsms_get_samples_to_process(FILE *fp);
long sbsms_get_frames_to_process(FILE *fp);
long sbsms_get_channels(FILE *fp);
void sbsms_get_quality(FILE *fp, sbsms_quality *quality);
void sbsms_seek_start_data(FILE *fp);
struct sbsmsInfo {
real rate0, rate1;
real pitch0, pitch1;
long samplesToProcess;
long samplesToGenerate;
Resampler *rs;
};
long getLinearOutputSamples(sbsmsInfo *si);
real rateCBLinear(long nProcessed, void *userData);
real rateCBConstant(long nProcessed, void *userData);
real pitchCBLinear(long nProcessed, void *userData);
real pitchCBConstant(long nProcessed, void *userData);
}
#endif

View File

@ -0,0 +1,40 @@
dnl @synopsis AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE])
dnl @summary check whether FLAGS are accepted by the compiler
dnl @category Misc
dnl
dnl Check whether the given compiler FLAGS work with the current language's
dnl compiler, or whether they give an error. (Warnings, however, are
dnl ignored.)
dnl
dnl ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
dnl success/failure.
dnl
dnl @version 2005-05-30
dnl @license GPLWithACException
dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Matteo Frigo.
AC_DEFUN([AX_CHECK_COMPILER_FLAGS],
[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX
AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])
dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
AS_LITERAL_IF([$1],
[AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [
ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])],
[ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes,
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no)
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])
eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)
AC_MSG_RESULT($ax_check_compiler_flags)
if test "x$ax_check_compiler_flags" = xyes; then
m4_default([$2], :)
else
m4_default([$3], :)
fi
])dnl AX_CHECK_COMPILER_FLAGS

View File

@ -0,0 +1,30 @@
dnl @synopsis AX_COMPILER_VENDOR
dnl @summary find the vendor (gnu, intel, etc.) of the C/C++ compiler
dnl @category C
dnl @category C++
dnl
dnl Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm,
dnl sun, hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi,
dnl microsoft, watcom, etc. The vendor is returned in the cache variable
dnl $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++.
dnl
dnl @version 2007-08-01
dnl @license GPLWithACException
dnl @author Steven G. Johnson <stevenj@alum.mit.edu> with Matteo Frigo
AC_DEFUN([AX_COMPILER_VENDOR],
[
AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
[ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
# note: don't check for gcc first since some other compilers define __GNUC__
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ pathscale:__PATHCC__,__PATHSCALE__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
#if !($vencpp)
thisisanerror;
#endif
])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break])
done
])
])

View File

@ -40,6 +40,8 @@ DIST_COMMON = $(libsbsmsinclude_HEADERS) $(srcdir)/Makefile.am \
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
$(top_srcdir)/m4/ac_c99_func_lrintf.m4 \
$(top_srcdir)/m4/ax_check_compiler_flags.m4 \
$(top_srcdir)/m4/ax_compiler_vendor.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.in
@ -59,9 +61,9 @@ am__installdirs = "$(DESTDIR)$(libdir)" \
libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES)
libsbsms_la_LIBADD =
am_libsbsms_la_OBJECTS = peak.lo sms.lo track.lo trackpoint.lo \
utils.lo audio.lo resample.lo sbsms.lo fft.lo grain.lo \
buffer.lo subband.lo
am_libsbsms_la_OBJECTS = sms.lo track.lo trackpoint.lo resample.lo \
sbsms.lo fft.lo grain.lo buffer.lo subband.lo dBTable.lo \
slide.lo
libsbsms_la_OBJECTS = $(am_libsbsms_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
@ -213,11 +215,11 @@ target_os = @target_os@
target_vendor = @target_vendor@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CXXFLAGS = -I../include @SBSMS_CFLAGS@
AM_CXXFLAGS = @SBSMS_CFLAGS@ -I../include
libsbsmsincludedir = $(includedir)
libsbsmsinclude_HEADERS = ../include/sbsms.h
lib_LTLIBRARIES = libsbsms.la
libsbsms_la_SOURCES = peak.cpp sms.cpp track.cpp trackpoint.cpp utils.cpp audio.cpp resample.cpp sbsms.cpp fft.cpp grain.cpp buffer.cpp subband.cpp audio.h buffer.h fft.h utils.h peak.h trackpoint.h grain.h real.h resample.h ../include/sbsms.h sms.h subband.h track.h
libsbsms_la_SOURCES = sms.cpp track.cpp trackpoint.cpp resample.cpp sbsms.cpp fft.cpp grain.cpp buffer.cpp subband.cpp dBTable.cpp buffer.h fft.h sse.h utils.h trackpoint.h grain.h real.h synthTable.h dBTable.h sincCoeffs.h ../include/sbsms.h sms.h subband.h track.h slide.cpp
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@ -305,18 +307,17 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dBTable.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fft.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grain.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peak.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resample.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sbsms.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slide.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sms.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subband.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/track.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trackpoint.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -1,41 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "audio.h"
namespace _sbsms_ {
audio *make_audio_buf(long n) {
return (audio*)calloc(n,sizeof(audio));
}
void free_audio_buf(audio *buf) {
free(buf);
}
long copy_audio_buf(audio *to, long off1, audio *from, long off2, long n)
{
memcpy(to+off1,from+off2,n*sizeof(audio));
return n;
}
long audio_convert_from(float *to, long off1, audio *from, long off2, long n)
{
for(int k=0;k<n;k++) {
int k2 = (k+off1)<<1;
to[k2] = (float)from[k+off2][0];
to[k2+1] = (float)from[k+off2][1];
}
return n;
}
long audio_convert_to(audio *to, long off1, float *from, long off2, long n)
{
for(int k=0;k<n;k++) {
int k2 = (k+off2)<<1;
to[k+off1][0] = (real)from[k2];
to[k+off1][1] = (real)from[k2+1];
}
return n;
}
}

View File

@ -1,16 +0,0 @@
#ifndef SBSMS_AUDIO_H
#define SBSMS_AUDIO_H
#include "sbsms.h"
namespace _sbsms_ {
audio *make_audio_buf(long);
void free_audio_buf(audio *);
long copy_audio_buf(audio *, long off1, audio *, long off2, long n);
long audio_convert_from(float *to, long off1, audio *from, long off2, long n);
long audio_convert_to(audio *to, long off1, float *from, long off2, long n);
}
#endif

View File

@ -9,162 +9,49 @@ using namespace std;
namespace _sbsms_ {
#define INIT_SAMPLEBUF_LENGTH 8192
#define INIT_GRAINBUF_LENGTH 128
#define INIT_TPLBUF_LENGTH 128
/****************
SampleBuf
****************/
SampleBuf :: SampleBuf(int N)
template<>
void SampleBuf :: write(grain *g, int h)
{
init(N,0);
}
SampleBuf :: SampleBuf(int N, long delay)
{
init(N,delay);
}
void SampleBuf :: init(int N, long delay)
{
this->delay = delay;
this->N = N;
this->length = INIT_SAMPLEBUF_LENGTH;
this->buf = make_audio_buf(2*length);
this->readPos = 0;
this->writePos = 0;
}
SampleBuf :: ~SampleBuf()
{
free_audio_buf(buf);
}
long SampleBuf :: write(audio *in, long n)
{
if(n==0) {
return 0;
}
grow(n);
memcpy(buf+writePos,in,n*sizeof(audio));
writePos += n;
return n;
}
void SampleBuf :: grow(long n)
{
long pos = writePos+n;
while(pos >= 2*length) {
length *= 2;
audio *newBuf = make_audio_buf(2*length);
memcpy(newBuf,buf+readPos,(length-readPos)*sizeof(audio));
free_audio_buf(buf);
buf = newBuf;
writePos -= readPos;
pos -= readPos;
readPos = 0;
}
}
long SampleBuf :: write(grain *g, int h)
{
grow(g->N);
grow(N);
g->synthesize();
real f = 2.6666666666666666666666666f/(real)(N/h);
float f = 2.6666666666666666666666666f/(float)(N/h);
for(int c=0;c<2;c++) {
int j = 0;
for(int k=writePos; k<writePos+g->N; k++) {
int kend = writePos + N;
for(int k=writePos; k<kend; k++) {
buf[k][c] += g->x[j++][c] * f;
}
}
writePos += h;
return h;
}
long SampleBuf :: read(audio *outBuf, long n)
GrainBuf :: GrainBuf(int N, int h, int N2, int type) :
grainAllocator(N,N2,type)
{
if(n==0)
return 0;
assert(writePos < 2*length);
n = min(n,n_readable());
n = max(n,(long)0);
memcpy(outBuf,buf+readPos,n*sizeof(audio));
return n;
}
long SampleBuf :: n_readable()
{
return max(writePos-delay - readPos,(long)0);
}
void SampleBuf :: advance(long n) {
assert(readPos+n <= writePos);
memset(buf+readPos,0,n*sizeof(audio));
readPos += n;
if(readPos >= length) {
long endPos;
if(N==0)
endPos = 2*length;
else
endPos = min(2*length,writePos+N);
memcpy(buf,buf+readPos,(endPos-readPos)*sizeof(audio));
memset(buf+readPos,0,(endPos-readPos)*sizeof(audio));
writePos -= readPos;
readPos = 0;
}
}
audio *SampleBuf :: getReadBuf()
{
return (buf+readPos);
}
void SampleBuf :: clear()
{
advance(writePos-readPos);
}
/****************
GrainBuf
****************/
GrainBuf :: GrainBuf(int N, int h)
{
init(N,h,1);
}
GrainBuf :: GrainBuf(int N, int h, real pad)
{
init(N,h,pad);
}
void GrainBuf :: init(int N, int h, real pad)
{
this->length = INIT_GRAINBUF_LENGTH;
this->length = initGrainBufLength;
this->buf = (grain**) calloc(2*length,sizeof(grain*));
this->iBuf = (audio*) calloc(N,sizeof(audio));
this->pad = pad;
this->N = N;
this->iBuf = (audio*) calloc(N2,sizeof(audio));
this->N2 = N2;
this->h = h;
this->overlap = N2 - h;
this->xOffset = (N-N2)>>1;
this->iBufWritePos = 0;
this->readPos = 0;
this->writePos = 0;
}
GrainBuf :: ~GrainBuf()
{
clear();
for(int k=readPos;k<writePos;k++) {
grainAllocator.forget(buf[k]);
}
free(buf);
free_audio_buf(iBuf);
free(iBuf);
}
audio *GrainBuf :: getWindowFFT()
{
return grainAllocator.W;
}
long GrainBuf :: write(audio *buf2, long n)
@ -173,48 +60,43 @@ long GrainBuf :: write(audio *buf2, long n)
return 0;
}
long ng = 0;
int overlap = N - h;
long bufReadPos = 0;
long nToCopy;
while(bufReadPos<n) {
long nToCopy = min((n-bufReadPos),N-iBufWritePos);
memcpy(iBuf+iBufWritePos, buf2+bufReadPos, nToCopy*sizeof(audio));
if(nToCopy+iBufWritePos == N) {
convert(iBuf);
nToCopy = min((n-bufReadPos),N2-iBufWritePos);
if(nToCopy+iBufWritePos == N2) {
if(buf2) {
memcpy(iBuf+iBufWritePos, buf2+bufReadPos, nToCopy*sizeof(audio));
} else {
memset(iBuf+iBufWritePos, 0, nToCopy*sizeof(audio));
}
grain *g = grainAllocator.create();
memcpy(g->x+xOffset,iBuf,N2*sizeof(audio));
write(g);
ng++;
memcpy(iBuf,iBuf+h,overlap*sizeof(audio));
iBufWritePos = overlap;
bufReadPos += nToCopy;
} else break;
}
// copy the remainder to the iBuf
long nToCopy = min((n-bufReadPos),N-iBufWritePos);
memcpy(iBuf+iBufWritePos, buf2+bufReadPos, nToCopy*sizeof(audio));
nToCopy = min((n-bufReadPos),N2-iBufWritePos);
if(buf2) {
memcpy(iBuf+iBufWritePos, buf2+bufReadPos, nToCopy*sizeof(audio));
} else {
memset(iBuf+iBufWritePos, 0, nToCopy*sizeof(audio));
}
iBufWritePos += nToCopy;
return ng;
}
void GrainBuf :: convert(audio *timebuf)
{
grain *g = grain::create(N,pad);
memcpy(g->x,timebuf,N*sizeof(audio));
g->analyze();
g->h = h;
write(g);
}
void GrainBuf :: advance(long n)
{
assert(readPos+n <= writePos);
for(int k=readPos;k<readPos+n;k++) {
grain :: forget(buf[k]);
grainAllocator.forget(buf[k]);
}
readPos += n;
//grain::count-=n;
if(readPos >= length) {
memcpy(buf,buf+readPos,(writePos-readPos)*sizeof(grain*));
writePos = writePos - readPos;
@ -227,35 +109,43 @@ grain* GrainBuf :: read(long k)
return buf[k];
}
long GrainBuf :: nReadable()
{
return writePos - readPos;
}
void GrainBuf :: write(grain *g)
{
if(writePos >= 2*length) {
length *= 2;
grain **newBuf = (grain**)calloc(2*length,sizeof(grain*));
if(writePos >= length<<1) {
length <<= 1;
grain **newBuf = (grain**)calloc((length<<1),sizeof(grain*));
memcpy(newBuf,buf+readPos,(writePos-readPos)*sizeof(grain*));
free(buf);
buf = newBuf;
writePos -= readPos;
readPos = 0;
}
grain :: referenced(g);
grainAllocator.reference(g);
buf[writePos++] = g;
}
void GrainBuf :: reference(grain *g)
{
grainAllocator.reference(g);
}
void GrainBuf :: forget(grain *g)
{
grainAllocator.forget(g);
}
void GrainBuf :: clear()
{
memset(iBuf,0,N*sizeof(audio));
memset(iBuf,0,N2*sizeof(audio));
iBufWritePos = 0;
advance(n_readable());
advance(writePos-readPos);
}
/****************
Mixer
****************/
Mixer :: Mixer(SampleBufBase *b1, SampleBuf *b2)
{
this->b1 = b1;
@ -264,86 +154,16 @@ Mixer :: Mixer(SampleBufBase *b1, SampleBuf *b2)
long Mixer :: read(audio *outBuf, long n)
{
if(n==0)
return 0;
n = min(n,n_readable());
b1->read(outBuf,n);
if(n==0) return 0;
n = min(n,b2->nReadable());
n = b1->read(outBuf,n);
audio *buf2 = b2->getReadBuf();
for(int k=0;k<n;k++) {
for(int c=0;c<2;c++)
outBuf[k][c] += buf2[k][c];
}
b2->advance(n);
return n;
}
void Mixer::advance(long n)
{
b1->advance(n);
b2->advance(n);
}
long Mixer::n_readable()
{
return min(b1->n_readable(), b2->n_readable());
}
/********************
TrackPointListBuffer
********************/
TrackPointListBuffer :: TrackPointListBuffer() {
length = INIT_TPLBUF_LENGTH;
buf = (tplist**) calloc(2*length,sizeof(tplist*));
readPos = 0;
writePos = 0;
}
TrackPointListBuffer :: ~TrackPointListBuffer() {
for(int k=readPos;k<writePos;k++)
delete buf[k];
free(buf);
}
long TrackPointListBuffer :: write(tplist *tpl)
{
if(writePos >= 2*length) {
length *= 2;
tplist **newBuf = (tplist**) calloc(2*length,sizeof(tplist*));
memcpy(newBuf,buf+readPos,(writePos-readPos)*sizeof(tplist*));
free(buf);
buf = newBuf;
writePos -= readPos;
readPos = 0;
}
buf[writePos++] = tpl;
return 1;
}
long TrackPointListBuffer :: n_readable()
{
return writePos-readPos;
}
tplist *TrackPointListBuffer :: read(long k)
{
return buf[k];
}
void TrackPointListBuffer :: advance(long n)
{
assert(readPos+n <= writePos);
for(int k=readPos;k<readPos+n;k++) {
delete buf[k];
}
readPos += n;
if(readPos >= length) {
memcpy(buf,buf+readPos,(writePos-readPos)*sizeof(tplist*));
writePos = writePos - readPos;
readPos = 0;
}
}
}

View File

@ -1,31 +1,31 @@
// -*- mode: c++ -*-
#ifndef BUFFER_H
#define BUFFER_H
#include <assert.h>
#include <cstring>
#include <cstdlib>
#include "sbsms.h"
#include "grain.h"
#include "trackpoint.h"
#include <list>
using namespace std;
namespace _sbsms_ {
typedef list<trackpoint*> tplist;
enum {
initSampleBufLength = 8192,
initGrainBufLength = 256,
initRingBufferLength = 64
};
template <class T>
class RingBuffer {
public:
RingBuffer();
~RingBuffer();
long write(T a);
T read(long k);
long n_readable();
T read();
long nReadable();
void advance(long n);
void clear();
long readPos;
long writePos;
protected:
@ -33,8 +33,6 @@ class RingBuffer {
long length;
};
#define INIT_RINGBUF_LENGTH 128
/********************
RingBuffer
********************/
@ -42,7 +40,7 @@ class RingBuffer {
template <class T>
RingBuffer<T> :: RingBuffer()
{
length = INIT_RINGBUF_LENGTH;
length = initRingBufferLength;
buf = (T*) calloc(2*length,sizeof(T));
readPos = 0;
writePos = 0;
@ -77,7 +75,13 @@ T RingBuffer<T> :: read(long k)
}
template <class T>
long RingBuffer<T> :: n_readable()
T RingBuffer<T> :: read()
{
return buf[readPos];
}
template <class T>
long RingBuffer<T> :: nReadable()
{
return writePos-readPos;
}
@ -85,7 +89,6 @@ long RingBuffer<T> :: n_readable()
template <class T>
void RingBuffer<T> :: advance(long n)
{
assert(readPos+n <= writePos);
readPos += n;
if(readPos >= length) {
memcpy(buf,buf+readPos,(writePos-readPos)*sizeof(T));
@ -101,64 +104,159 @@ void RingBuffer<T> :: clear()
writePos = 0;
}
class TrackPointListBuffer {
class SampleBufBase {
public:
TrackPointListBuffer();
~TrackPointListBuffer();
long write(tplist *tpl);
tplist *read(long k);
long n_readable();
void advance(long n);
long readPos;
long writePos;
protected:
tplist **buf;
long length;
SampleBufBase() {};
virtual ~SampleBufBase() {};
virtual long read(audio *buf, long n)=0;
};
/****************
SampleBuf
****************/
class grain;
template<class T>
class ArrayRingBuffer
{
public:
ArrayRingBuffer(int N);
virtual ~ArrayRingBuffer();
void clear();
void grow(long pos);
void write(T *buf, long n);
void write(grain *g, int h);
void read(T *buf, long n);
void advance(long n);
long nReadable();
T *getReadBuf();
long readPos, writePos;
int N;
long length;
T *buf;
};
template<class T>
ArrayRingBuffer<T> :: ArrayRingBuffer(int N)
{
this->N = N;
this->length = initSampleBufLength;
this->buf = (T*)calloc(2*length,sizeof(T));
this->readPos = 0;
this->writePos = 0;
}
template<class T>
ArrayRingBuffer<T> :: ~ArrayRingBuffer()
{
free(buf);
}
template<class T>
void ArrayRingBuffer<T> :: write(T *in, long n)
{
grow(n);
if(in) memcpy(buf+writePos,in,n*sizeof(T));
writePos += n;
}
template<class T>
void ArrayRingBuffer<T> :: grow(long n)
{
long pos = writePos+n;
while(pos >= 2*length) {
length *= 2;
T *newBuf = (T*)calloc(2*length,sizeof(T));
memcpy(newBuf,buf+readPos,(length-readPos)*sizeof(T));
free(buf);
buf = newBuf;
writePos -= readPos;
pos -= readPos;
readPos = 0;
}
}
template<class T>
void ArrayRingBuffer<T> :: read(T *outBuf, long n)
{
n = max(0L,min(n,nReadable()));
memcpy(outBuf,buf+readPos,n*sizeof(T));
advance(n);
}
template<class T>
long ArrayRingBuffer<T> :: nReadable()
{
return max(0L,writePos-readPos);
}
template<class T>
void ArrayRingBuffer<T> :: advance(long n) {
memset(buf+readPos,0,n*sizeof(T));
readPos += n;
if(readPos >= length) {
long endPos;
endPos = writePos+N;
memcpy(buf,buf+readPos,(endPos-readPos)*sizeof(T));
memset(buf+readPos,0,((length<<1)-readPos)*sizeof(T));
writePos -= readPos;
readPos = 0;
}
}
template<class T>
T *ArrayRingBuffer<T> :: getReadBuf()
{
return (buf+readPos);
}
template<class T>
void ArrayRingBuffer<T> :: clear()
{
advance(writePos-readPos);
}
typedef ArrayRingBuffer<audio> SampleBuf;
class GrainBuf {
public:
GrainBuf(int N, int h);
GrainBuf(int N, int h, real pad);
GrainBuf(int N, int h, int N2, int type);
~GrainBuf();
void init(int N, int h, real pad);
long write(audio *buf, long n);
void write(grain *g);
void advance(long n);
long n_readable() { return writePos - readPos; }
long nReadable();
void clear();
grain* read(long k);
long length;
long readPos, writePos;
int N,h;
real pad;
void reference(grain *g);
void forget(grain *g);
audio *getWindowFFT();
long readPos;
long writePos;
protected:
void convert(audio *buf);
audio *iBuf;
long iBufWritePos;
grain **buf;
long length;
long N2;
long h;
long overlap;
long xOffset;
long iBufWritePos;
GrainAllocator grainAllocator;
};
class Mixer : public SampleBufBase {
public:
Mixer(SampleBufBase *, SampleBuf *);
long read(audio *buf, long n);
void advance(long n);
long n_readable();
~Mixer() {}
virtual long read(audio *buf, long n);
protected:
SampleBuf *buf;
SampleBufBase *b1;
SampleBuf *b2;
SampleBuf *b2;
};
}

View File

@ -1,14 +1,14 @@
/* src/config.h.in. Generated from configure.in by autoheader. */
/* Define to enable sse */
#undef ENABLE_SSE
/* Define to 1 if you have the `calloc' function. */
#undef HAVE_CALLOC
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the `floor' function. */
#undef HAVE_FLOOR
/* Define to 1 if you have the `free' function. */
#undef HAVE_FREE
@ -18,18 +18,12 @@
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the `log' function. */
#undef HAVE_LOG
/* Define if you have C99's lrint function. */
#undef HAVE_LRINT
/* Define if you have C99's lrintf function. */
#undef HAVE_LRINTF
/* Define to use libmad */
#undef HAVE_MAD
/* Define to 1 if you have the `malloc' function. */
#undef HAVE_MALLOC
@ -39,14 +33,8 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to use libportaudio */
#undef HAVE_PORTAUDIO
/* Define to use libsndfile */
#undef HAVE_SNDFILE
/* Define to 1 if you have the `sqrt' function. */
#undef HAVE_SQRT
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
// -*- mode: c++ -*-
#ifndef DBTABLE_H
#define DBTABLE_H
#include "real.h"
namespace _sbsms_ {
enum { dBTableSize = 4096, dBTableScale = dBTableSize - 1 };
extern float dBTable[dBTableSize];
inline float dBApprox(float x, float y)
{
if(x < y) {
return dBTable[lrintf(x/y*dBTableScale)];
} else if(x == 0.0f) {
return 0;
} else {
return dBTable[lrintf(y/x*dBTableScale)];
}
}
}
#endif

View File

@ -1,737 +1,35 @@
#include "fft.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include "utils.h"
namespace _sbsms_ {
#define REAL(tr,ti,r,i) (tr*r - ti*i)
#define IMAG(tr,ti,r,i) (tr*i + ti*r)
t_fft *make_fft_buf(int N)
void fft128(t_fft *x)
{
return (t_fft*) malloc(N*sizeof(t_fft));
fft<128,1>(x);
}
void free_fft_buf(t_fft *buf)
void ifft128(t_fft *x)
{
free(buf);
fft<128,-1>(x);
}
void optimizeFactors(int *f)
void fft256(t_fft *x)
{
int n = 0;
for(int k=0;;k++) {
if(f[k]==0) break;
n++;
}
int *g = (int*)calloc(n+1,sizeof(int));
for(int k=0;k<n;k++) {
g[k] = f[k];
}
int m = 0;
for(int k=0;k<n;k++) {
int f2 = g[k] * g[k+1];
if(f2 == 6) {
f[m++] = 6;
k++;
} else if(f2 == 4) {
f[m++] = 4;
k++;
} else {
f[m++] = g[k];
}
}
f[m] = 0;
free(g);
fft<256,1>(x);
}
int *getOrder(int n, int *N1, int *N2)
void ifft256(t_fft *x)
{
int N = N1[0]*N2[0];
int *order = (int*)calloc(N,sizeof(int));
for(int k=0;k<N;k++) {
int kr = 0;
int k0 = k;
for(int i=0;i<n;i++) {
int k2 = k0%N2[i];
k0 /= N2[i];
kr += N1[i]*k2;
}
order[k] = kr;
}
return order;
fft<256,-1>(x);
}
t_fft **calcTwiddles(int n, int *N1, int *N2, int *order, int sign)
void fft384(t_fft *x)
{
t_fft **t = (t_fft**)calloc(n,sizeof(t_fft*));
for(int i=0;i<n;i++) {
int Np = N1[i]*N2[i];
t[i] = (t_fft*)calloc(Np,sizeof(t_fft));
for(int k=0;k<Np;k++) {
t[i][k][0] = cos((real)(-sign)*TWOPI*(real)k/(real)Np);
t[i][k][1] = sin((real)(-sign)*TWOPI*(real)k/(real)Np);
}
}
return t;
fft<384,1>(x);
}
fft_func *getFuncs(int *f)
void fft512(t_fft *x)
{
int n = 0;
for(int k=0;;k++) {
if(f[k] == 0) break;
n++;
}
fft_func *func = (fft_func*)calloc(n,sizeof(fft_func));
for(int k=0;k<n;k++) {
switch(f[k]) {
case 2 : func[k] = fft2; break;
case 3 : func[k] = fft3; break;
case 4 : func[k] = fft4; break;
case 5 : func[k] = fft5; break;
case 6 : func[k] = fft6; break;
case 7 : func[k] = fft7; break;
}
}
return func;
}
int *getN1(int *f, int N)
{
int n = 0;
for(int k=0;;k++) {
if(f[k] == 0) break;
n++;
}
int *N1 = (int*)calloc(n,sizeof(int));
for(int k=0;k<n;k++) {
N /= f[k];
N1[k] = N;
}
return N1;
}
int getNFactors(int *f)
{
int n = 0;
for(int k=0;;k++) {
if(f[k] == 0) break;
n++;
}
return n;
}
fftplan *planFFT(int N)
{
int *factors = factor(N);
optimizeFactors(factors);
fftplan *plan = new fftplan;
plan->dir = 1;
plan->n = getNFactors(factors);
plan->N2 = factors;
plan->N1 = getN1(factors,N);
plan->order = getOrder(plan->n,plan->N1,plan->N2);
plan->reorder = (t_fft*)malloc(N*sizeof(t_fft));
plan->t = calcTwiddles(plan->n,plan->N1,plan->N2,plan->order,1);
plan->f = getFuncs(factors);
plan->N = N;
plan->norm = 1.0;
return plan;
}
fftplan *planIFFT(int N)
{
int *factors = factor(N);
optimizeFactors(factors);
fftplan *plan = new fftplan;
plan->dir = -1;
plan->n = getNFactors(factors);
plan->N2 = factors;
plan->N1 = getN1(factors,N);
plan->order = getOrder(plan->n,plan->N1,plan->N2);
plan->reorder = (t_fft*)malloc(N*sizeof(t_fft));
plan->t = calcTwiddles(plan->n,plan->N1,plan->N2,plan->order,-1);
plan->f = getFuncs(factors);
plan->N = N;
plan->norm = 1.0f/(real)N;
return plan;
}
void destroy_fftplan(fftplan *plan)
{
free(plan->reorder);
free(plan->order);
free(plan->f);
for(int i=0;i<plan->n;i++)
free(plan->t[i]);
free(plan->t);
free(plan->N1);
free(plan->N2);
free(plan);
}
void FFT(fftplan *plan, t_fft *x)
{
fft(plan,x,0,0);
for(int k=0;k<plan->N;k++) {
plan->reorder[k][0] = x[k][0];
plan->reorder[k][1] = x[k][1];
}
for(int k=0;k<plan->N;k++) {
int kr = plan->order[k];
if(k != kr) {
x[k][0] = plan->reorder[kr][0];
x[k][1] = plan->reorder[kr][1];
}
}
}
void IFFT(fftplan *plan, t_fft *x)
{
FFT(plan,x);
/*
real norm = plan->norm;
for(int k=0;k<plan->N;k++) {
x[k][0] *= norm;
x[k][1] *= norm;
}
*/
}
void fft(fftplan *plan, t_fft *x, int r, int i)
{
int N1 = plan->N1[i];
int N2 = plan->N2[i];
for(int n1=0;n1<N1;n1++) {
(plan->f[i])(x,n1,N1,r,plan->t[i],plan->dir);
}
if(N1==1) return;
for(int k2=0;k2<N2;k2++) {
fft(plan,x,r,i+1);
r += N1;
}
}
void fft2(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+= N1;
real *x1 = x[i];
real y0 = x0[0] - x1[0];
real y1 = x0[1] - x1[1];
x0[0] += x1[0];
x0[1] += x1[1];
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,y0,y1);
x1[1] = IMAG(t10,t11,y0,y1);
}
#define T300 0.5f
#define T301 0.86602540378444f
void fft3(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+=N1;
real *x1 = x[i]; i+=N1;
real *x2 = x[i];
real z00 = x1[0] + x2[0];
real z01 = x1[1] + x2[1];
real z10 = x0[0] - T300*z00;
real z11 = x0[1] - T300*z01;
real z20;
real z21;
if(dir==1) {
z20 = T301*(x2[0] - x1[0]);
z21 = T301*(x2[1] - x1[1]);
} else {
z20 = T301*(x1[0] - x2[0]);
z21 = T301*(x1[1] - x2[1]);
}
x0[0] = z00 + x0[0];
x0[1] = z01 + x0[1];
real z30 = z10 - z21;
real z31 = z11 + z20;
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,z30,z31);
x1[1] = IMAG(t10,t11,z30,z31);
real z40 = z10 + z21;
real z41 = z11 - z20;
real *t2 = t[n1<<1];
real t20 = t2[0];
real t21 = t2[1];
x2[0] = REAL(t20,t21,z40,z41);
x2[1] = IMAG(t20,t21,z40,z41);
}
void fft4(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+=N1;
real *x1 = x[i]; i+=N1;
real *x2 = x[i]; i+=N1;
real *x3 = x[i];
real z20 = x0[0] - x2[0];
real z21 = x0[1] - x2[1];
real z00 = x0[0] + x2[0];
real z01 = x0[1] + x2[1];
real z10 = x1[0] + x3[0];
real z11 = x1[1] + x3[1];
x0[0] = z00 + z10;
x0[1] = z01 + z11;
real y20 = z00 - z10;
real y21 = z01 - z11;
real *t2 = t[n1<<1];
real t20 = t2[0];
real t21 = t2[1];
x2[0] = REAL(t20,t21,y20,y21);
x2[1] = IMAG(t20,t21,y20,y21);
real z30;
real z31;
if(dir==1) {
z30 = (x3[0] - x1[0]);
z31 = (x3[1] - x1[1]);
} else {
z30 = (x1[0] - x3[0]);
z31 = (x1[1] - x3[1]);
}
real y10 = z20 - z31;
real y11 = z21 + z30;
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,y10,y11);
x1[1] = IMAG(t10,t11,y10,y11);
real y30 = z20 + z31;
real y31 = z21 - z30;
real *t3 = t[n1*3];
real t30 = t3[0];
real t31 = t3[1];
x3[0] = REAL(t30,t31,y30,y31);
x3[1] = IMAG(t30,t31,y30,y31);
}
#define T500 0.95105651629515f
#define T501 0.58778525229247f
#define T510 0.55901699437495f
#define T511 0.25f
void fft5(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+=N1;
real *x1 = x[i]; i+=N1;
real *x2 = x[i]; i+=N1;
real *x3 = x[i]; i+=N1;
real *x4 = x[i];
real z00 = x1[0] + x4[0];
real z01 = x1[1] + x4[1];
real z10 = x2[0] + x3[0];
real z11 = x2[1] + x3[1];
real z20 = x1[0] - x4[0];
real z21 = x1[1] - x4[1];
real z30 = x2[0] - x3[0];
real z31 = x2[1] - x3[1];
real z40 = z00 + z10;
real z41 = z01 + z11;
real z50 = T510*(z00 - z10);
real z51 = T510*(z01 - z11);
real z60 = x0[0] - T511*z40;
real z61 = x0[1] - T511*z41;
real z70 = z50 + z60;
real z71 = z51 + z61;
real z80 = z60 - z50;
real z81 = z61 - z51;
real z90;
real z91;
if(dir==1) {
z90 = -(T500*z20 + T501*z30);
z91 = -(T500*z21 + T501*z31);
} else {
z90 = (T500*z20 + T501*z30);
z91 = (T500*z21 + T501*z31);
}
real z100;
real z101;
if(dir==1) {
z100 = (T500*z30 - T501*z20);
z101 = (T500*z31 - T501*z21);
} else {
z100 = (T501*z20 - T500*z30);
z101 = (T501*z21 - T500*z31);
}
x0[0] = x0[0] + z40;
x0[1] = x0[1] + z41;
real y10 = z70 - z91;
real y11 = z71 + z90;
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,y10,y11);
x1[1] = IMAG(t10,t11,y10,y11);
real y20 = z80 - z101;
real y21 = z81 + z100;
real *t2 = t[n1<<1];
real t20 = t2[0];
real t21 = t2[1];
x2[0] = REAL(t20,t21,y20,y21);
x2[1] = IMAG(t20,t21,y20,y21);
real y30 = z80 + z101;
real y31 = z81 - z100;
real *t3 = t[n1*3];
real t30 = t3[0];
real t31 = t3[1];
x3[0] = REAL(t30,t31,y30,y31);
x3[1] = IMAG(t30,t31,y30,y31);
real y40 = z70 + z91;
real y41 = z71 - z90;
real *t4 = t[n1<<2];
real t40 = t4[0];
real t41 = t4[1];
x4[0] = REAL(t40,t41,y40,y41);
x4[1] = IMAG(t40,t41,y40,y41);
}
#define T600 0.86602540378444f
#define T601 0.5f
void fft6(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+=N1;
real *x1 = x[i]; i+=N1;
real *x2 = x[i]; i+=N1;
real *x3 = x[i]; i+=N1;
real *x4 = x[i]; i+=N1;
real *x5 = x[i];
real za00 = x2[0] + x4[0];
real za01 = x2[1] + x4[1];
real za10 = x0[0] - T601*za00;
real za11 = x0[1] - T601*za01;
real za20;
real za21;
if(dir==1) {
za20 = T600*(x4[0] - x2[0]);
za21 = T600*(x4[1] - x2[1]);
} else {
za20 = T600*(x2[0] - x4[0]);
za21 = T600*(x2[1] - x4[1]);
}
real a00 = x0[0] + za00;
real a01 = x0[1] + za01;
real a10 = za10 - za21;
real a11 = za11 + za20;
real a20 = za10 + za21;
real a21 = za11 - za20;
real zb00 = x1[0] + x5[0];
real zb01 = x1[1] + x5[1];
real zb10 = x3[0] - T601*zb00;
real zb11 = x3[1] - T601*zb01;
real zb20;
real zb21;
if(dir==1) {
zb20 = T600*(x1[0] - x5[0]);
zb21 = T600*(x1[1] - x5[1]);
} else {
zb20 = T600*(x5[0] - x1[0]);
zb21 = T600*(x5[1] - x1[1]);
}
real b00 = x3[0] + zb00;
real b01 = x3[1] + zb01;
real b10 = zb10 - zb21;
real b11 = zb11 + zb20;
real b20 = zb10 + zb21;
real b21 = zb11 - zb20;
x0[0] = a00 + b00;
x0[1] = a01 + b01;
real y10 = a10 - b10;
real y11 = a11 - b11;
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,y10,y11);
x1[1] = IMAG(t10,t11,y10,y11);
real y20 = a20 + b20;
real y21 = a21 + b21;
real *t2 = t[n1<<1];
real t20 = t2[0];
real t21 = t2[1];
x2[0] = REAL(t20,t21,y20,y21);
x2[1] = IMAG(t20,t21,y20,y21);
real y30 = a00 - b00;
real y31 = a01 - b01;
real *t3 = t[n1*3];
real t30 = t3[0];
real t31 = t3[1];
x3[0] = REAL(t30,t31,y30,y31);
x3[1] = IMAG(t30,t31,y30,y31);
real y40 = a10 + b10;
real y41 = a11 + b11;
real *t4 = t[n1<<2];
real t40 = t4[0];
real t41 = t4[1];
x4[0] = REAL(t40,t41,y40,y41);
x4[1] = IMAG(t40,t41,y40,y41);
real y50 = a20 - b20;
real y51 = a21 - b21;
real *t5 = t[n1*5];
real t50 = t5[0];
real t51 = t5[1];
x5[0] = REAL(t50,t51,y50,y51);
x5[1] = IMAG(t50,t51,y50,y51);
}
#define C71 -1.16666666666667f
#define C72 0.79015646852540f
#define C73 0.05585426728965f
#define C74 0.73430220123575f
#define C75 0.44095855184410f
#define C76 0.34087293062393f
#define C77 -0.53396936033773f
#define C78 0.87484229096166f
void fft7(t_fft *x, int n1, int N1, int r, t_fft *t, int dir)
{
int i = r+n1;
real *x0 = x[i]; i+=N1;
real *x1 = x[i]; i+=N1;
real *x2 = x[i]; i+=N1;
real *x3 = x[i]; i+=N1;
real *x4 = x[i]; i+=N1;
real *x5 = x[i]; i+=N1;
real *x6 = x[i];
real u00 = x1[0] + x6[0];
real u01 = x1[1] + x6[1];
real u10 = x1[0] - x6[0];
real u11 = x1[1] - x6[1];
real u20 = x2[0] + x5[0];
real u21 = x2[1] + x5[1];
real u30 = x2[0] - x5[0];
real u31 = x2[1] - x5[1];
real u40 = x4[0] + x3[0];
real u41 = x4[1] + x3[1];
real u50 = x4[0] - x3[0];
real u51 = x4[1] - x3[1];
real u60 = u20 + u00;
real u61 = u21 + u01;
real u70 = u50 + u30;
real u71 = u51 + u31;
real b00 = x0[0] + u60 + u40;
real b01 = x0[1] + u61 + u41;
real b10 = C71*(u60 + u40);
real b11 = C71*(u61 + u41);
real b20 = C72*(u00 - u40);
real b21 = C72*(u01 - u41);
real b30 = C73*(u40 - u20);
real b31 = C73*(u41 - u21);
real b40 = C74*(u20 - u00);
real b41 = C74*(u21 - u01);
real b50;
real b51;
if(dir==1) {
b50 = C75*(u70 + u10);
b51 = C75*(u71 + u11);
} else {
b50 = -C75*(u70 + u10);
b51 = -C75*(u71 + u11);
}
real b60;
real b61;
if(dir==1) {
b60 = C76*(u10 - u50);
b61 = C76*(u11 - u51);
} else {
b60 = C76*(u50 - u10);
b61 = C76*(u51 - u11);
}
real b70;
real b71;
if(dir==1) {
b70 = C77*(u50 - u30);
b71 = C77*(u51 - u31);
} else {
b70 = C77*(u30 - u50);
b71 = C77*(u31 - u51);
}
real b80;
real b81;
if(dir==1) {
b80 = C78*(u30 - u10);
b81 = C78*(u31 - u11);
} else {
b80 = C78*(u10 - u30);
b81 = C78*(u11 - u31);
}
real T00 = b00 + b10;
real T01 = b01 + b11;
real T10 = b20 + b30;
real T11 = b21 + b31;
real T20 = b40 - b30;
real T21 = b41 - b31;
real T30 = -b20 - b40;
real T31 = -b21 - b41;
real T40 = b60 + b70;
real T41 = b61 + b71;
real T50 = b80 - b70;
real T51 = b81 - b71;
real T60 = -b80 - b60;
real T61 = -b81 - b61;
real T70 = T00 + T10;
real T71 = T01 + T11;
real T80 = T00 + T20;
real T81 = T01 + T21;
real T90 = T00 + T30;
real T91 = T01 + T31;
real T100 = T40 + b50;
real T101 = T41 + b51;
real T110 = T50 + b50;
real T111 = T51 + b51;
real T120 = T60 + b50;
real T121 = T61 + b51;
x0[0] = b00;
x0[1] = b01;
real y10 = T70 + T101;
real y11 = T71 - T100;
real *t1 = t[n1];
real t10 = t1[0];
real t11 = t1[1];
x1[0] = REAL(t10,t11,y10,y11);
x1[1] = IMAG(t10,t11,y10,y11);
real y20 = T90 + T121;
real y21 = T91 - T120;
real *t2 = t[n1<<1];
real t20 = t2[0];
real t21 = t2[1];
x2[0] = REAL(t20,t21,y20,y21);
x2[1] = IMAG(t20,t21,y20,y21);
real y30 = T80 - T111;
real y31 = T81 + T110;
real *t3 = t[n1*3];
real t30 = t3[0];
real t31 = t3[1];
x3[0] = REAL(t30,t31,y30,y31);
x3[1] = IMAG(t30,t31,y30,y31);
real y40 = T80 + T111;
real y41 = T81 - T110;
real *t4 = t[n1<<2];
real t40 = t4[0];
real t41 = t4[1];
x4[0] = REAL(t40,t41,y40,y41);
x4[1] = IMAG(t40,t41,y40,y41);
real y50 = T90 - T121;
real y51 = T91 + T120;
real *t5 = t[n1*5];
real t50 = t5[0];
real t51 = t5[1];
x5[0] = REAL(t50,t51,y50,y51);
x5[1] = IMAG(t50,t51,y50,y51);
real y60 = T70 - T101;
real y61 = T71 + T100;
real *t6 = t[n1*6];
real t60 = t6[0];
real t61 = t6[1];
x6[0] = REAL(t60,t61,y60,y61);
x6[1] = IMAG(t60,t61,y60,y61);
fft<512,1>(x);
}
}

View File

@ -1,51 +1,853 @@
// -*- mode: c++ -*-
#ifndef FFT_H
#define FFT_H
#include "sbsms.h"
#include <math.h>
#include <string.h>
#include "utils.h"
#ifdef ENABLE_SSE
#include "sse.h"
#endif
namespace _sbsms_ {
typedef real t_fft[2];
typedef void (*fftplan)(t_fft *x);
void fft128(t_fft *x);
void ifft128(t_fft *x);
void fft256(t_fft *x);
void ifft256(t_fft *x);
void fft384(t_fft *x);
void fft512(t_fft *x);
typedef void (*fft_func)(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
struct fftplan {
fft_func *f;
int *order;
t_fft *reorder;
int *N1;
int *N2;
int N;
int n;
int dir;
real norm;
t_fft **t;
template<int N>
class Factor {
public:
enum { value = (N%8==0)?8:(N%7==0)?7:(N%4==0)?4:(N%5==0)?5:(N%6==0)?6:(N%3==0)?3:(N%2==0)?2:1 };
};
t_fft *make_fft_buf(int N);
void free_fft_buf(t_fft *buf);
fftplan *planFFT(int N);
fftplan *planIFFT(int N);
void destroy_fftplan(fftplan *plan);
void FFT(fftplan *plan, t_fft *x);
void IFFT(fftplan *plan, t_fft *x);
template<int N>
class LastFactor {
public:
enum { radix = Factor<N>::value,
stride = N / radix,
value = (stride==1?radix:LastFactor<stride>::value) };
};
void fft(fftplan *plan, t_fft *x, int r, int i);
void optimizeFactors(int *f);
int *getOrder(int n, int *N1, int *N2);
t_fft **calcTwiddles(int n, int *N1, int *N2, int dir);
fft_func *getFuncs(int *f);
int *getN1(int *f, int N);
int getNFactors(int *f);
template <>
class LastFactor<1> {
public:
enum { value = 1 };
};
void fft2(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
void fft3(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
void fft4(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
void fft5(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
void fft6(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
void fft7(t_fft *x, int n1, int N1, int r, t_fft *t, int dir);
template<int istride, int ostride, int radix, int dir>
class __fft {
public:
static inline void execute(t_fft *x, t_fft *y, int step);
};
template <int N, int dir>
class FloatTwiddles {
public:
float c[N];
float s[N];
FloatTwiddles() {
for(int k=0; k<N; k++) {
c[k] = cos(TWOPI * (float)k / (float)N);
s[k] = sin(TWOPI * (float)(-dir*k) / (float)N);
}
}
};
template <int N, int dir>
class FloatTwiddle {
public:
static const float *c;
static const float *s;
static const FloatTwiddles<N,dir> t;
static inline void twiddle(int k, t_fft *x, float r, float i) {
float cc = c[k];
float ss = s[k];
(*x)[0] = cc * r - ss * i;
(*x)[1] = ss * r + cc * i;
}
};
template <int N, int dir>
const FloatTwiddles<N,dir> FloatTwiddle<N,dir>::t;
template <int N, int dir>
const float* FloatTwiddle<N,dir>::c = t.c;
template <int N, int dir>
const float* FloatTwiddle<N,dir>::s = t.s;
template<int istride, int ostride, int dir>
class __fft<istride,ostride,2,dir> {
public:
enum { i1 = istride, o1 = ostride,
ir0 = 0, ii0 = 1, or0 = 0, oi0 = 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float y0 = x[ir0] - x[ir1]; float y1 = x[ii0] - x[ii1];
y[or0] = x[ir0] + x[ir1]; y[oi0] = x[ii0] + x[ii1];
y[or1] = y0; y[oi1] = y1;
}
};
template<int istride, int ostride, int dir>
class __fft<istride,ostride,3,dir> {
public:
enum { N = istride * 3,
i1_ = istride, o1 = ostride,
i2_ = istride + istride, o2 = o1 + ostride,
i1 = (dir==1?i1_:i2_),
i2 = (dir==1?i2_:i1_),
ir0 = 0, ii0 = 1, or0 = 0, oi0 = 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float z00 = x[ir1] + x[ir2]; float z01 = x[ii1] + x[ii2];
float z10 = x[ir0] - 0.5f*z00; float z11 = x[ii0] - 0.5f*z01;
float z20 = 0.86602540378444f*(x[ir2] - x[ir1]); float z21 = 0.86602540378444f*(x[ii2] - x[ii1]);
y[or0] = x[ir0] + z00; y[oi0] = x[ii0] + z01;
if(step) {
FloatTwiddle<N,dir>::twiddle(step, _y+o1,z10 - z21,z11 + z20);
FloatTwiddle<N,dir>::twiddle(step+step, _y+o2,z10 + z21,z11 - z20);
} else {
y[or1] = z10 - z21; y[oi1] = z11 + z20;
y[or2] = z10 + z21; y[oi2] = z11 - z20;
}
}
};
template<int istride, int ostride, int dir>
class __fft<istride,ostride,5,dir> {
public:
enum { N = istride*5,
i0 = 0, o0 = 0,
i1_ = i0 + istride, o1 = o0 + ostride,
i2_ = i1_ + istride, o2 = o1 + ostride,
i3_ = i2_ + istride, o3 = o2 + ostride,
i4_ = i3_ + istride, o4 = o3 + ostride,
i1 = (dir==1?i4_:i1_),
i2 = (dir==1?i3_:i2_),
i3 = (dir==1?i2_:i3_),
i4 = (dir==1?i1_:i4_),
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1,
ir4 = i4<<1, ii4 = ir4 + 1, or4 = o4<<1, oi4 = or4 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float z00, z01, z10, z11, z20, z21, z30, z31, z40, z41, z50, z51, z60, z61, z70, z71, z80, z81, z90, z91, z100, z101;
z00 = x[ir1] + x[ir4]; z01 = x[ii1] + x[ii4];
z10 = x[ir2] + x[ir3]; z11 = x[ii2] + x[ii3];
z20 = x[ir1] - x[ir4]; z21 = x[ii1] - x[ii4];
z30 = x[ir2] - x[ir3]; z31 = x[ii2] - x[ii3];
z40 = z00 + z10; z41 = z01 + z11;
z50 = 0.55901699437495f*(z00 - z10); z51 = 0.55901699437495f*(z01 - z11);
z60 = x[ir0] - 0.25f*z40; z61 = x[ii0] - 0.25f*z41;
z70 = z50 + z60; z71 = z51 + z61;
z80 = z60 - z50; z81 = z61 - z51;
z90 = 0.95105651629515f*z20 + 0.58778525229247f*z30; z91 = 0.95105651629515f*z21 + 0.58778525229247f*z31;
z100 = 0.58778525229247f*z20 - 0.95105651629515f*z30; z101 = 0.58778525229247f*z21 - 0.95105651629515f*z31;
y[or0] = x[ir0] + z40; y[oi0] = x[ii0] + z41;
if(step) {
int step2 = step + step;
FloatTwiddle<N,dir>::twiddle(step,_y+o1,z70 - z91,z71 + z90);
FloatTwiddle<N,dir>::twiddle(step2,_y+o2,z80 - z101,z81 + z100);
FloatTwiddle<N,dir>::twiddle(step2+step,_y+o3,z80 + z101,z81 - z100);
FloatTwiddle<N,dir>::twiddle(step2+step2,_y+o4,z70 + z91,z71 - z90);
} else {
y[or1] = z70 - z91; y[oi1] = z71 + z90;
y[or2] = z80 - z101; y[oi2] = z81 + z100;
y[or3] = z80 + z101; y[oi3] = z81 - z100;
y[or4] = z70 + z91; y[oi4] = z71 - z90;
}
}
};
template<int istride, int ostride, int dir>
class __fft<istride,ostride,6,dir> {
public:
enum { N = istride*6,
i0 = 0, o0 = 0,
i1_ = i0 + istride, o1 = o0 + ostride,
i2_ = i1_ + istride, o2 = o1 + ostride,
i3 = i2_ + istride, o3 = o2 + ostride,
i4_ = i3 + istride, o4 = o3 + ostride,
i5_ = i4_ + istride, o5 = o4 + ostride,
i1 = (dir==1?i1_:i5_),
i2 = (dir==1?i2_:i4_),
i4 = (dir==1?i4_:i2_),
i5 = (dir==1?i5_:i1_),
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1,
ir4 = i4<<1, ii4 = ir4 + 1, or4 = o4<<1, oi4 = or4 + 1,
ir5 = i5<<1, ii5 = ir5 + 1, or5 = o5<<1, oi5 = or5 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float za00, za01, za10, za11, za20, za21;
float a00, a01, a10, a11, a20, a21;
float zb00, zb01, zb10, zb11, zb20, zb21;
float b00, b01, b10, b11, b20, b21;
za00 = x[ir2] + x[ir4]; za01 = x[ii2] + x[ii4];
za10 = x[ir0] - 0.5f*za00; za11 = x[ii0] - 0.5f*za01;
za20 = 0.86602540378444f*(x[ir4] - x[ir2]); za21 = 0.86602540378444f*(x[ii4] - x[ii2]);
a00 = x[ir0] + za00; a01 = x[ii0] + za01;
a10 = za10 - za21; a11 = za11 + za20;
a20 = za10 + za21; a21 = za11 - za20;
zb00 = x[ir1] + x[ir5]; zb01 = x[ii1] + x[ii5];
zb10 = x[ir3] - 0.5f*zb00; zb11 = x[ii3] - 0.5f*zb01;
zb20 = 0.86602540378444f*(x[ir1] - x[ir5]); zb21 = 0.86602540378444f*(x[ii1] - x[ii5]);
b00 = x[ir3] + zb00; b01 = x[ii3] + zb01;
b10 = zb10 - zb21; b11 = zb11 + zb20;
b20 = zb10 + zb21; b21 = zb11 - zb20;
y[or0] = a00 + b00; y[oi0] = a01 + b01;
if(step) {
FloatTwiddle<N,dir>::twiddle(step,_y+o1,a10 - b10,a11 - b11);
int step2 = step + step;
FloatTwiddle<N,dir>::twiddle(step2,_y+o2,a20 + b20,a21 + b21);
int step3 = step2 + step;
FloatTwiddle<N,dir>::twiddle(step3,_y+o3,a00 - b00,a01 - b01);
FloatTwiddle<N,dir>::twiddle(step2+step2,_y+o4,a10 + b10,a11 + b11);
FloatTwiddle<N,dir>::twiddle(step3+step2,_y+o5,a20 - b20,a21 - b21);
} else {
y[or1] = a10 - b10; y[oi1] = a11 - b11;
y[or2] = a20 + b20; y[oi2] = a21 + b21;
y[or3] = a00 - b00; y[oi3] = a01 - b01;
y[or4] = a10 + b10; y[oi4] = a11 + b11;
y[or5] = a20 - b20; y[oi5] = a21 - b21;
}
}
};
template<int istride, int ostride, int dir>
class __fft<istride,ostride,7,dir> {
public:
enum { N = istride*7,
i0 = 0, o0 = 0,
i1 = i0 + istride, o1 = o0 + ostride,
i2 = i1 + istride, o2 = o1 + ostride,
i3 = i2 + istride, o3 = o2 + ostride,
i4 = i3 + istride, o4 = o3 + ostride,
i5 = i4 + istride, o5 = o4 + ostride,
i6 = i5 + istride, o6 = o5 + ostride,
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1,
ir4 = i4<<1, ii4 = ir4 + 1, or4 = o4<<1, oi4 = or4 + 1,
ir5 = i5<<1, ii5 = ir5 + 1, or5 = o5<<1, oi5 = or5 + 1,
ir6 = i6<<1, ii6 = ir6 + 1, or6 = o6<<1, oi6 = or6 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float u00, u01, u10, u11, u20, u21, u30, u31, u40, u41, u50, u51, u60, u61, u70, u71;
float b00, b01, b10, b11, b20, b21, b30, b31, b40, b41, b50, b51, b60, b61, b70, b71, b80, b81;
float T00, T01, T10, T11, T20, T21, T30, T31, T40, T41, T50, T51, T60, T61, T70, T71, T80, T81, T90, T91, T100, T101, T110, T111, T120, T121;
u00 = x[ir1] + x[ir6]; u01 = x[ii1] + x[ii6];
u10 = x[ir1] - x[ir6]; u11 = x[ii1] - x[ii6];
u20 = x[ir2] + x[ir5]; u21 = x[ii2] + x[ii5];
u30 = x[ir2] - x[ir5]; u31 = x[ii2] - x[ii5];
u40 = x[ir4] + x[ir3]; u41 = x[ii4] + x[ii3];
u50 = x[ir4] - x[ir3]; u51 = x[ii4] - x[ii3];
u60 = u20 + u00; u61 = u21 + u01;
u70 = u50 + u30; u71 = u51 + u31;
b00 = x[ir0] + u60 + u40; b01 = x[ii0] + u61 + u41;
b10 = -1.16666666666667f*(u60 + u40); b11 = -1.16666666666667f*(u61 + u41);
b20 = 0.79015646852540f*(u00 - u40); b21 = 0.79015646852540f*(u01 - u41);
b30 = 0.05585426728965f*(u40 - u20); b31 = 0.05585426728965f*(u41 - u21);
b40 = 0.73430220123575f*(u20 - u00); b41 = 0.73430220123575f*(u21 - u01);
if(dir==1) {
b50 = 0.44095855184410f*(u70 + u10);
b51 = 0.44095855184410f*(u71 + u11);
b60 = 0.34087293062393f*(u10 - u50);
b61 = 0.34087293062393f*(u11 - u51);
b70 = -0.53396936033773f*(u50 - u30);
b71 = -0.53396936033773f*(u51 - u31);
b80 = 0.87484229096166f*(u30 - u10);
b81 = 0.87484229096166f*(u31 - u11);
} else {
b50 = -0.44095855184410f*(u70 + u10);
b51 = -0.44095855184410f*(u71 + u11);
b60 = 0.34087293062393f*(u50 - u10);
b61 = 0.34087293062393f*(u51 - u11);
b70 = -0.53396936033773f*(u30 - u50);
b71 = -0.53396936033773f*(u31 - u51);
b80 = 0.87484229096166f*(u10 - u30);
b81 = 0.87484229096166f*(u11 - u31);
}
T00 = b00 + b10; T01 = b01 + b11;
T10 = b20 + b30; T11 = b21 + b31;
T20 = b40 - b30; T21 = b41 - b31;
T30 = -b20 - b40; T31 = -b21 - b41;
T40 = b60 + b70; T41 = b61 + b71;
T50 = b80 - b70; T51 = b81 - b71;
T60 = -b80 - b60; T61 = -b81 - b61;
T70 = T00 + T10; T71 = T01 + T11;
T80 = T00 + T20; T81 = T01 + T21;
T90 = T00 + T30; T91 = T01 + T31;
T100 = T40 + b50; T101 = T41 + b51;
T110 = T50 + b50; T111 = T51 + b51;
T120 = T60 + b50; T121 = T61 + b51;
y[or0] = b00; y[oi0] = b01;
if(step) {
FloatTwiddle<N,dir>::twiddle(step,_y+o1,T70 + T101,T71 - T100);
int step2 = step + step;
FloatTwiddle<N,dir>::twiddle(step2,_y+o2,T90 + T121,T91 - T120);
int step3 = step2 + step;
FloatTwiddle<N,dir>::twiddle(step3,_y+o3,T80 - T111,T81 + T110);
FloatTwiddle<N,dir>::twiddle(step2+step2,_y+o4,T80 + T111,T81 - T110);
FloatTwiddle<N,dir>::twiddle(step3+step2,_y+o5,T90 - T121,T91 + T120);
FloatTwiddle<N,dir>::twiddle(step3+step3,_y+o6,T70 - T101,T71 + T100);
} else {
y[or1] = T70 + T101; y[oi1] = T71 - T100;
y[or2] = T90 + T121; y[oi2] = T91 - T120;
y[or3] = T80 - T111; y[oi3] = T81 + T110;
y[or4] = T80 + T111; y[oi4] = T81 - T110;
y[or5] = T90 - T121; y[oi5] = T91 + T120;
y[or6] = T70 - T101; y[oi6] = T71 + T100;
}
}
};
#ifdef ENABLE_SSE
template <int N, int dir>
class SSETwiddles {
public:
simd_vector cs[N];
SSETwiddles() {
for(int k=0; k<N; k++) {
float c = cos(TWOPI * (float)k / (float)N);
float s = sin(TWOPI * (float)(-dir*k) / (float)N);
simd_vector v = {c,s,c,-s};
cs[k] = v;
}
}
};
template <int N, int dir>
class SSETwiddle {
public:
static const SSETwiddles<N,dir> t;
static const simd_vector *cs;
static inline simd_vector twiddle(int k, const simd_vector &v) {
return VMUL(cs[k],v);
}
static inline void twiddle(int k, t_fft *x, const simd_vector &v) {
simd_vector y = twiddle(k,v);
simd_vector z = VADD(SHUFFLE(y,y,0,1,0,1),SHUFFLE(y,y,3,2,3,2));
STOREL(z,x);
}
static inline void twiddle2(int k1, int k2, t_fft *x1, t_fft *x2, const simd_vector &y1, const simd_vector &y2) {
simd_vector v1 = VMUL(cs[k1],y1);
simd_vector v2 = VMUL(cs[k2],y2);
simd_vector z = VADD(SHUFFLE(v1,v2,0,1,0,1),SHUFFLE(v1,v2,3,2,3,2));
STOREL(z,x1);
STOREH(z,x2);
}
};
template <int N, int dir>
const SSETwiddles<N,dir> SSETwiddle<N,dir>::t;
template <int N, int dir>
const simd_vector* SSETwiddle<N,dir>::cs = t.cs;
template<int istride, int ostride, int dir>
class __fft<istride,ostride,4,dir> {
public:
enum { N = istride * 4,
ir0 = 0, or0 = 0,
_ir1 = ir0 + istride, or1 = or0 + ostride,
ir2 = _ir1 + istride, or2 = or1 + ostride,
_ir3 = ir2 + istride, or3 = or2 + ostride,
ir1 = (dir==1?_ir3:_ir1),
ir3 = (dir==1?_ir1:_ir3) };
static inline void execute(t_fft *x, t_fft *y, int step) {
simd_vector v1;
simd_vector v2;
simd_vector v3;
simd_vector v4;
simd_vector v5;
v1 = LOADH(LOADL(v1,x+ir0),x+ir1);
v2 = LOADH(LOADL(v2,x+ir2),x+ir3);
v3 = VADD(v1,v2);
v4 = VSUB(v1,v2);
v1 = SHUFFLE(v4,v3,0,1,0,1);
v2 = SHUFFLE(v4,v3,3,2,2,3);
v3 = VADD(v1,v2);
STOREH(v3,y+or0);
v4 = VSUB(v1,v2);
v1 = SHUFFLE(v4,v3,0,0,1,1);
v2 = SHUFFLE(v4,v4,2,2,3,3);
v5 = SHUFFLE(v3,v4,0,0,1,1);
if(step) {
v1 = SSETwiddle<N,dir>::twiddle(step,v1);
int step2 = step + step;
v2 = SSETwiddle<N,dir>::twiddle(step2,v2);
v3 = SSETwiddle<N,dir>::twiddle(step2+step,v5);
v3 = VADD(v3,SHUFFLE(v3,v3,3,2,1,0));
STOREL(v3,y+or3);
v5 = VADD(SHUFFLE(v1,v2,0,1,0,1),SHUFFLE(v1,v2,3,2,3,2));
STOREL(v5,y+or1);
STOREH(v5,y+or2);
} else {
v5 = SHUFFLE(v5,v5,0,2,0,2);
STOREL(v5,y+or3);
v3 = SHUFFLE(v1,v2,0,2,0,2);
STOREL(v3,y+or1);
STOREH(v3,y+or2);
}
}
};
template<int istride, int ostride>
class __fft<istride,ostride,8,1> {
public:
enum { N = istride*8,
i0 = 0, o0 = 0,
i1 = i0 + istride, o1 = o0 + ostride,
i2 = i1 + istride, o2 = o1 + ostride,
i3 = i2 + istride, o3 = o2 + ostride,
i4 = i3 + istride, o4 = o3 + ostride,
i5 = i4 + istride, o5 = o4 + ostride,
i6 = i5 + istride, o6 = o5 + ostride,
i7 = i6 + istride, o7 = o6 + ostride };
static inline void execute(t_fft *x, t_fft *y, int step) {
simd_vector v1,v2,v3,v4,v5,v6,v7,v8;
simd_vector x02,x37,x15,x17,x53,x46;
simd_vector w1, w2, w3, w4;
w1 = LOADH(LOADL(w1,x+i0),x+i6);
w2 = LOADH(LOADL(w2,x+i4),x+i2);
w3 = VADD(w1,w2);
w4 = VSUB(w1,w2);
v1 = LOADH(LOADL(v1,x+i1),x+i7);
v2 = LOADH(LOADL(v2,x+i5),x+i3);
v3 = VADD(v1,v2);
v4 = VSUB(v1,v2);
v5 = SHUFFLE(v3,v4,2,1,0,1); //(z10,z01,z20,z21)
v6 = SHUFFLE(v3,v4,0,3,3,2); //(z00,z11,z31,z30)
v7 = VADD(v5,v6); // (x1,y30,y11)
v8 = VSUB(v5,v6); // (x51,x50,y10,y31)
x15 = SHUFFLE(v7,v8,0,1,1,0); //(x1,x5)
v2 = SHUFFLE(v8,v8,3,3,3,2); //(-,-,y31,y10)
v3 = VADD(v7,v2);
v4 = VSUB(v7,v2);
v5 = SHUFFLE(v3,v4,2,3,2,3);
x37 = VMUL(SET(0.7071067811865475f),v5); //(-x71,x30,-x70,x31)
v5 = SHUFFLE(w3,w4,0,1,0,1); //(z00,z01,z20,z21)
v6 = SHUFFLE(w3,w4,2,3,3,2); //(z10,z11,z31,z30)
v7 = VADD(v5,v6); //(x0,y30,y11)
v8 = VSUB(v5,v6); //(x4,y10,y31)
v1 = SHUFFLE(v7,v8,0,1,0,1); //(x0,x4)
v2 = SHUFFLE(v8,v7,3,2,2,3); //(x61,x20,x60,x21)
x02 = VADD(v1,x15);
x46 = VSUB(v1,x15);
x17 = VADD(v2,x37);
x53 = VSUB(v2,x37);
STOREL(x02,y+o0);
if(step) {
simd_vector y1;
simd_vector y2;
int step2 = step + step;
y1 = SHUFFLE(x02,x02,2,2,3,3);
SSETwiddle<N,1>::twiddle(step2,y+o2,y1);
int step3 = step2 + step;
y1 = SHUFFLE(x53,x53,1,1,3,3);
y2 = SHUFFLE(x53,x53,2,2,0,0);
SSETwiddle<N,1>::twiddle2(step3+step2,step3,y+o5,y+o3,y1,y2);
int step4 = step2 + step2;
y1 = SHUFFLE(x46,x46,0,0,1,1);
y2 = SHUFFLE(x46,x46,2,2,3,3);
SSETwiddle<N,1>::twiddle2(step4,step3+step3,y+o4,y+o6,y1,y2);
y1 = SHUFFLE(x17,x17,1,1,3,3);
y2 = SHUFFLE(x17,x17,2,2,0,0);
SSETwiddle<N,1>::twiddle2(step,step4+step3,y+o1,y+o7,y1,y2);
} else {
simd_vector y1;
y1 = SHUFFLE(x02,x02,2,3,3,3);
STOREL(y1,y+o2);
y1 = SHUFFLE(x53,x53,1,3,2,0);
STOREL(y1,y+o5);
STOREH(y1,y+o3);
STOREL(x46,y+o4);
STOREH(x46,y+o6);
y1 = SHUFFLE(x17,x17,1,3,2,0);
STOREL(y1,y+o1);
STOREH(y1,y+o7);
}
}
};
template<int istride, int ostride>
class __fft<istride,ostride,8,-1> {
public:
enum { N = istride*8,
i0 = 0, o0 = 0,
i1 = i0 + istride, o1 = o0 + ostride,
i2 = i1 + istride, o2 = o1 + ostride,
i3 = i2 + istride, o3 = o2 + ostride,
i4 = i3 + istride, o4 = o3 + ostride,
i5 = i4 + istride, o5 = o4 + ostride,
i6 = i5 + istride, o6 = o5 + ostride,
i7 = i6 + istride, o7 = o6 + ostride };
static inline void execute(t_fft *x, t_fft *y, int step) {
simd_vector v1,v2,v3,v4,v5,v6,v7,v8;
simd_vector x02,x37,x15,x17,x53,x46;
simd_vector w1, w2, w3, w4;
w1 = LOADH(LOADL(w1,x+i0),x+i2);
w2 = LOADH(LOADL(w2,x+i4),x+i6);
w3 = VADD(w1,w2);
w4 = VSUB(w1,w2);
v1 = LOADH(LOADL(v1,x+i1),x+i3);
v2 = LOADH(LOADL(v2,x+i5),x+i7);
v3 = VADD(v1,v2);
v4 = VSUB(v1,v2);
v5 = SHUFFLE(v3,v4,0,3,0,1);
v6 = SHUFFLE(v3,v4,2,1,3,2);
v7 = VADD(v5,v6);
v8 = VSUB(v5,v6);
x15 = SHUFFLE(v7,v8,0,1,1,0);
v2 = SHUFFLE(v8,v8,3,3,3,2);
v3 = VADD(v7,v2);
v4 = VSUB(v2,v7);
v5 = SHUFFLE(v4,v3,2,3,2,3);
x37 = VMUL(SET(0.7071067811865475f),v5);
v5 = SHUFFLE(w3,w4,0,1,0,1);
v6 = SHUFFLE(w3,w4,2,3,3,2);
v7 = VADD(v5,v6);
v8 = VSUB(v5,v6);
v1 = SHUFFLE(v7,v8,0,1,0,1);
v2 = SHUFFLE(v8,v7,3,2,2,3);
x02 = VADD(v1,x15);
x46 = VSUB(v1,x15);
x17 = VADD(v2,x37);
x53 = VSUB(v2,x37);
STOREL(x02,y+o0);
if(step) {
simd_vector y1;
simd_vector y2;
int step2 = step + step;
y1 = SHUFFLE(x02,x02,2,2,3,3);
SSETwiddle<N,-1>::twiddle(step2,y+o2,y1);
int step3 = step2 + step;
y1 = SHUFFLE(x53,x53,1,1,3,3);
y2 = SHUFFLE(x53,x53,2,2,0,0);
SSETwiddle<N,-1>::twiddle2(step3+step2,step3,y+o5,y+o3,y1,y2);
int step4 = step2 + step2;
y1 = SHUFFLE(x46,x46,0,0,1,1);
y2 = SHUFFLE(x46,x46,2,2,3,3);
SSETwiddle<N,-1>::twiddle2(step4,step3+step3,y+o4,y+o6,y1,y2);
y1 = SHUFFLE(x17,x17,1,1,3,3);
y2 = SHUFFLE(x17,x17,2,2,0,0);
SSETwiddle<N,-1>::twiddle2(step,step4+step3,y+o1,y+o7,y1,y2);
} else {
simd_vector y1;
y1 = SHUFFLE(x02,x02,2,3,3,3);
STOREL(y1,y+o2);
y1 = SHUFFLE(x53,x53,1,3,2,0);
STOREL(y1,y+o5);
STOREH(y1,y+o3);
STOREL(x46,y+o4);
STOREH(x46,y+o6);
y1 = SHUFFLE(x17,x17,1,3,2,0);
STOREL(y1,y+o1);
STOREH(y1,y+o7);
}
}
};
#else // !ENABLE_SSE
template<int istride, int ostride, int dir>
class __fft<istride,ostride,4,dir> {
public:
enum { N = istride*4,
i0 = 0, o0 = 0,
i1_ = i0 + istride, o1 = o0 + ostride,
i2 = i1_ + istride, o2 = o1 + ostride,
i3_ = i2 + istride, o3 = o2 + ostride,
i1 = (dir==1?i1_:i3_),
i3 = (dir==1?i3_:i1_),
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float z00, z01, z10, z11, z20, z21, z30, z31;
z20 = x[ir0] - x[ir2]; z21 = x[ii0] - x[ii2];
z00 = x[ir0] + x[ir2]; z01 = x[ii0] + x[ii2];
z10 = x[ir1] + x[ir3]; z11 = x[ii1] + x[ii3];
y[or0] = z00 + z10; y[oi0] = z01 + z11;
z30 = x[ir3] - x[ir1]; z31 = x[ii3] - x[ii1];
if(step) {
int step2 = step + step;
FloatTwiddle<N,dir>::twiddle(step,_y+o1,z20 - z31,z21 + z30);
FloatTwiddle<N,dir>::twiddle(step2,_y+o2,z00 - z10,z01 - z11);
FloatTwiddle<N,dir>::twiddle(step2+step,_y+o3,z20 + z31,z21 - z30);
} else {
y[or1] = z20 - z31; y[oi1] = z21 + z30;
y[or2] = z00 - z10; y[oi2] = z01 - z11;
y[or3] = z20 + z31; y[oi3] = z21 - z30;
}
}
};
template<int istride, int ostride>
class __fft<istride,ostride,8,1> {
public:
enum { N = istride*8,
i0 = 0, o0 = 0,
i1 = i0 + istride, o1 = o0 + ostride,
i2 = i1 + istride, o2 = o1 + ostride,
i3 = i2 + istride, o3 = o2 + ostride,
i4 = i3 + istride, o4 = o3 + ostride,
i5 = i4 + istride, o5 = o4 + ostride,
i6 = i5 + istride, o6 = o5 + ostride,
i7 = i6 + istride, o7 = o6 + ostride,
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1,
ir4 = i4<<1, ii4 = ir4 + 1, or4 = o4<<1, oi4 = or4 + 1,
ir5 = i5<<1, ii5 = ir5 + 1, or5 = o5<<1, oi5 = or5 + 1,
ir6 = i6<<1, ii6 = ir6 + 1, or6 = o6<<1, oi6 = or6 + 1,
ir7 = i7<<1, ii7 = ir7 + 1, or7 = o7<<1, oi7 = or7 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float z00, z01, z10, z11, z20, z21, z30, z31, y10, y11, y30, y31;
float yr0, yi0, yr1, yi1, yr2, yi2, yr3, yi3, yr4, yi4, yr5, yi5, yr6, yi6, yr7, yi7;
z00 = x[ir1] + x[ir5]; z01 = x[ii1] + x[ii5];
z10 = x[ir7] + x[ir3]; z11 = x[ii7] + x[ii3];
z20 = x[ir1] - x[ir5]; z21 = x[ii1] - x[ii5];
z30 = x[ir7] - x[ir3]; z31 = x[ii7] - x[ii3];
y10 = z20 - z31; y11 = z21 + z30;
y30 = z20 + z31; y31 = z21 - z30;
yr1 = z00 + z10; yi1 = z01 + z11;
yr5 = z01 - z11; yi5 = z10 - z00;
yr3 = 0.7071067811865475f * (y10 + y11); yi3 = 0.7071067811865475f * (y11 - y10);
yr7 = 0.7071067811865475f * (y31 - y30); yi7 = -0.7071067811865475f * (y30 + y31);
z20 = x[ir0] - x[ir4]; z21 = x[ii0] - x[ii4];
z00 = x[ir0] + x[ir4]; z01 = x[ii0] + x[ii4];
z10 = x[ir6] + x[ir2]; z11 = x[ii6] + x[ii2];
z30 = x[ir6] - x[ir2]; z31 = x[ii6] - x[ii2];
yr0 = z00 + z10; yi0 = z01 + z11;
yr4 = z00 - z10; yi4 = z01 - z11;
yr2 = z20 - z31; yi2 = z21 + z30;
yr6 = z20 + z31; yi6 = z21 - z30;
y[or0] = yr0 + yr1; y[oi0] = yi0 + yi1;
if(step) {
FloatTwiddle<N,1>::twiddle(step,_y+o1,yr2 + yr3, yi2 + yi3);
int step2 = step + step;
FloatTwiddle<N,1>::twiddle(step2,_y+o2,yr4 + yr5, yi4 + yi5);
int step3 = step2 + step;
FloatTwiddle<N,1>::twiddle(step3,_y+o3,yr6 + yr7, yi6 + yi7);
FloatTwiddle<N,1>::twiddle(step2+step2,_y+o4,yr0 - yr1, yi0 - yi1);
FloatTwiddle<N,1>::twiddle(step3+step2,_y+o5,yr2 - yr3, yi2 - yi3);
FloatTwiddle<N,1>::twiddle(step3+step3,_y+o6,yr4 - yr5, yi4 - yi5);
FloatTwiddle<N,1>::twiddle(step3+step2+step2,_y+o7,yr6 - yr7, yi6 - yi7);
} else {
y[or1] = yr2 + yr3; y[oi1] = yi2 + yi3;
y[or2] = yr4 + yr5; y[oi2] = yi4 + yi5;
y[or3] = yr6 + yr7; y[oi3] = yi6 + yi7;
y[or4] = yr0 - yr1; y[oi4] = yi0 - yi1;
y[or5] = yr2 - yr3; y[oi5] = yi2 - yi3;
y[or6] = yr4 - yr5; y[oi6] = yi4 - yi5;
y[or7] = yr6 - yr7; y[oi7] = yi6 - yi7;
}
}
};
template<int istride, int ostride>
class __fft<istride,ostride,8,-1> {
public:
enum { N = istride*8,
i0 = 0, o0 = 0,
i1 = i0 + istride, o1 = o0 + ostride,
i2 = i1 + istride, o2 = o1 + ostride,
i3 = i2 + istride, o3 = o2 + ostride,
i4 = i3 + istride, o4 = o3 + ostride,
i5 = i4 + istride, o5 = o4 + ostride,
i6 = i5 + istride, o6 = o5 + ostride,
i7 = i6 + istride, o7 = o6 + ostride,
ir0 = i0<<1, ii0 = ir0 + 1, or0 = o0<<1, oi0 = or0 + 1,
ir1 = i1<<1, ii1 = ir1 + 1, or1 = o1<<1, oi1 = or1 + 1,
ir2 = i2<<1, ii2 = ir2 + 1, or2 = o2<<1, oi2 = or2 + 1,
ir3 = i3<<1, ii3 = ir3 + 1, or3 = o3<<1, oi3 = or3 + 1,
ir4 = i4<<1, ii4 = ir4 + 1, or4 = o4<<1, oi4 = or4 + 1,
ir5 = i5<<1, ii5 = ir5 + 1, or5 = o5<<1, oi5 = or5 + 1,
ir6 = i6<<1, ii6 = ir6 + 1, or6 = o6<<1, oi6 = or6 + 1,
ir7 = i7<<1, ii7 = ir7 + 1, or7 = o7<<1, oi7 = or7 + 1 };
static inline void execute(t_fft *_x, t_fft *_y, int step) {
float *x = (float*)_x;
float *y = (float*)_y;
float z00, z01, z10, z11, z20, z21, z30, z31, y10, y11, y30, y31;
float yr0, yi0, yr1, yi1, yr2, yi2, yr3, yi3, yr4, yi4, yr5, yi5, yr6, yi6, yr7, yi7;
z00 = x[ir1] + x[ir5]; z01 = x[ii1] + x[ii5];
z10 = x[ir3] + x[ir7]; z11 = x[ii3] + x[ii7];
z20 = x[ir1] - x[ir5]; z21 = x[ii1] - x[ii5];
z30 = x[ir3] - x[ir7]; z31 = x[ii3] - x[ii7];
y10 = z20 - z31; y11 = z21 + z30;
y30 = z20 + z31; y31 = z21 - z30;
yr1 = z00 + z10; yi1 = z01 + z11;
yr5 = z11 - z01; yi5 = z00 - z10;
yr3 = 0.7071067811865475f * (y10 - y11); yi3 = 0.7071067811865475f * (y10 + y11);
yr7 = -0.7071067811865475f * (y30 + y31); yi7 = 0.7071067811865475f * (y30 - y31);
z00 = x[ir0] + x[ir4]; z01 = x[ii0] + x[ii4];
z10 = x[ir2] + x[ir6]; z11 = x[ii2] + x[ii6];
z20 = x[ir0] - x[ir4]; z21 = x[ii0] - x[ii4];
z30 = x[ir2] - x[ir6]; z31 = x[ii2] - x[ii6];
yr0 = z00 + z10; yi0 = z01 + z11;
yr4 = z00 - z10; yi4 = z01 - z11;
yr2 = z20 - z31; yi2 = z21 + z30;
yr6 = z20 + z31; yi6 = z21 - z30;
y[or0] = yr0 + yr1;
y[oi0] = yi0 + yi1;
if(step) {
FloatTwiddle<N,-1>::twiddle(step,_y+o1,yr2 + yr3, yi2 + yi3);
int step2 = step + step;
FloatTwiddle<N,-1>::twiddle(step2,_y+o2,yr4 + yr5, yi4 + yi5);
int step3 = step2 + step;
FloatTwiddle<N,-1>::twiddle(step3,_y+o3,yr6 + yr7, yi6 + yi7);
FloatTwiddle<N,-1>::twiddle(step2+step2,_y+o4,yr0 - yr1, yi0 - yi1);
FloatTwiddle<N,-1>::twiddle(step3+step2,_y+o5,yr2 - yr3, yi2 - yi3);
FloatTwiddle<N,-1>::twiddle(step3+step3,_y+o6,yr4 - yr5, yi4 - yi5);
FloatTwiddle<N,-1>::twiddle(step3+step2+step2,_y+o7,yr6 - yr7, yi6 - yi7);
} else {
y[or1] = yr2 + yr3; y[oi1] = yi2 + yi3;
y[or2] = yr4 + yr5; y[oi2] = yi4 + yi5;
y[or3] = yr6 + yr7; y[oi3] = yi6 + yi7;
y[or4] = yr0 - yr1; y[oi4] = yi0 - yi1;
y[or5] = yr2 - yr3; y[oi5] = yi2 - yi3;
y[or6] = yr4 - yr5; y[oi6] = yi4 - yi5;
y[or7] = yr6 - yr7; y[oi7] = yi6 - yi7;
}
}
};
#endif // ENABLE_SSE
template<int k, int stride, int radix, int dir>
class _fft {
public:
enum { N = radix * stride,
_radix = Factor<stride>::value,
_stride = stride / _radix };
static inline void execute(t_fft *x) {
for(int step=0; step<stride; step++) {
__fft<stride,stride,radix,dir>::execute(x+step,x+step,step);
}
_fft<N,_stride,_radix,dir>::loop(x+N);
}
static inline void loop(t_fft *x) {
_fft<k-N,stride,radix,dir>::execute(x-N);
_fft<k-N,stride,radix,dir>::loop(x-N);
}
};
template<int stride, int radix, int dir>
class _fft<0,stride,radix,dir> {
public:
enum { N = radix * stride,
_radix = Factor<stride>::value,
_stride = stride / _radix };
static inline void execute(t_fft *x) {
for(int step=0; step<stride; step++) {
__fft<stride,stride,radix,dir>::execute(x+step,x+step,step);
}
_fft<N,_stride,_radix,dir>::loop(x+N);
}
static inline void loop(t_fft *x) { }
};
template <int k, int radix, int dir>
class _fft<k,1,radix,dir> {
public:
static inline void execute(t_fft *x) { }
static inline void loop(t_fft *x) { }
};
template <int radix, int dir>
class _fft<0,1,radix,dir> {
public:
static inline void execute(t_fft *x) { }
static inline void loop(t_fft *x) { }
};
template<int N>
class fft_order_ {
public:
static inline int iterate(int k) {
static const int N2 = Factor<N>::value;
static const int N1 = N/Factor<N>::value;
return (k%N2)*N1 + fft_order_<N1>::iterate(k/N2);
}
};
template<>
class fft_order_<1> {
public:
static inline int iterate(int k0) {
return 0;
}
};
template<int N>
class fft_order {
public:
fft_order<N>() {
for(int k=0;k<N;k++) {
int kr = fft_order_<N>::iterate(k);
order[kr] = k;
}
}
int order[N];
};
template<int N, int dir>
class fft_reorder {
public:
enum { radix = LastFactor<N>::value,
ostride = N / radix,
s = N * sizeof(t_fft) };
static const fft_order<N> order;
static inline void reorder(t_fft *x) {
t_fft y[N];
int *o = (int*)order.order;
memcpy(y,x,s);
for(int r=0; r<N; r+=radix) {
__fft<1,ostride,radix,dir>::execute(y+r,x+o[r],0);
}
}
};
template<int N, int dir>
const fft_order<N> fft_reorder<N,dir>::order;
template<int N, int dir>
void fft(t_fft *x) {
enum { radix = Factor<N>::value,
stride = N / radix };
_fft<0,stride,radix,dir>::execute(x);
fft_reorder<N,dir>::reorder(x);
}
}
#endif

View File

@ -11,136 +11,132 @@ using namespace std;
namespace _sbsms_ {
map<int, map<real, real*> > wwMap;
map<int, map<real, audio*> > peakMap;
map<int, fftplan*> fftPlanMap;
map<int, fftplan*> ifftPlanMap;
grain* grain :: create(int N,real pad)
GrainAllocator :: GrainAllocator(int N, int N2, int type)
{
grain *g = new grain(N,pad);
this->N = N;
this->N2 = N2;
this->type = type;
switch(N) {
case 128:
fftPlan = &fft128;
ifftPlan = &ifft128;
break;
case 256:
fftPlan = &fft256;
ifftPlan = &ifft256;
break;
case 384:
fftPlan = &fft384;
//ifftPlan = &ifft384;
break;
case 512:
fftPlan = &fft512;
//ifftPlan = &ifft512;
break;
default:
abort();
break;
}
int k1 = (N-N2)/2;
w = (float*)calloc(N,sizeof(float));
for(int k=0;k<N2;k++) {
if(type == hann) {
w[k+k1] = 0.5f*(1.0f - cos((float)k/(float)N2*TWOPI));
} else if(type == hannpoisson) {
w[k+k1] = 0.5f*(1.0f - cos((float)k/(float)N2*TWOPI)) * exp(-2.0f*fabs((float)(k-N2/2))/(float)N2);
}
}
W = (audio*) calloc(N,sizeof(audio));
for(int k=0;k<N;k++) {
W[k][0] = w[k] * 2.638502561913447f/(float)N2;
}
fftPlan(W);
}
GrainAllocator :: ~GrainAllocator()
{
free(w);
free(W);
}
grain* GrainAllocator :: create()
{
grain *g = new grain(N,N2);
g->refCount = 0;
g->fftPlan = fftPlan;
g->ifftPlan = ifftPlan;
g->w = w;
return g;
}
void grain :: referenced(grain *g)
void GrainAllocator :: reference(grain *g)
{
g->refCount++;
}
void grain :: forget(grain *g)
void GrainAllocator :: forget(grain *g)
{
g->refCount--;
if(g->refCount <= 0) {
destroy(g);
delete g;
}
}
void grain :: destroy(grain *g)
grain :: grain(int N, int N2)
{
free_audio_buf(g->x);
delete g;
}
grain :: grain(int N, real pad)
{
this->N = N;
this->pad = pad;
calc_plans();
calc_windows();
refCount = 0;
x = (audio*) malloc(N*sizeof(audio));
this->synthScale = 1.0f / (float)N2;
x = (audio*) calloc(N,sizeof(audio));
}
void grain :: analyze()
grain :: ~grain()
{
for(int k=0;k<N;k++) {
for(int c=0;c<2;c++) {
x[k][c] *= ww[k];
}
free(x);
}
void grain :: analyze()
{
float *x = (float*)this->x;
float *end = x + (N<<1);
float *w = this->w;
while(x != end) {
*(x++) *= *w;
*(x++) *= *(w++);
}
FFT(fftPlan,x);
fftPlan(this->x);
}
void grain :: synthesize()
{
IFFT(ifftPlan,x);
real f = pad/(real)N;
ifftPlan(x);
for(int k=0;k<N;k++) {
for(int c=0;c<2;c++) {
x[k][c] *= ww[k] * f;
x[k][c] *= w[k] * synthScale;
}
}
}
void grain :: calc_plans()
void grain :: downsample(grain *g2)
{
fftPlan = fftPlanMap[N];
if(fftPlan == NULL) {
fftPlanMap[N] = (fftPlan = planFFT(N));
}
ifftPlan = ifftPlanMap[N];
if(ifftPlan == NULL) {
ifftPlanMap[N] = (ifftPlan = planIFFT(N));
}
}
void grain :: calc_windows()
{
int N2 = round2int(N/pad);
ww = wwMap[N][pad];
if(ww == NULL) {
wwMap[N][pad] = (ww = (real*)calloc(N,sizeof(real)));
for(int k=0;k<N2;k++) {
ww[k+(N-N2)/2] = 0.5f*(1.0f - cos((real)k/(real)N2*TWOPI));
}
}
peak = peakMap[N][pad];
if(peak == NULL) {
peakMap[N][pad] = (peak = (audio*) calloc(N,sizeof(audio)));
for(int k=0;k<N;k++) {
peak[k][0] = ww[k]/(real)(N2/2);
}
FFT(fftPlan,peak);
}
}
grain* grain :: upsample()
{
grain *g2 = grain::create(2*N,pad);
grain *g = this;
int N2 = N/2;
int N4 = N/4;
for(int c=0;c<2;c++) {
for(int k=0;k<=N/2;k++)
g2->x[k][c] = g->x[k][c];
for(int k=N/2+1;k<=N/2+N;k++)
g2->x[k][c] = 0;
for(int k=N/2+N+1;k<2*N;k++)
g2->x[k][c] = g->x[k-N][c];
for(int k=0;k<N4;k++) {
g2->x[k][c] = 0.5f * g->x[k][c];
}
g2->x[N4][c] = 0.25f * (g->x[N4][c] + g->x[N-N4][c]);
for(int k=N4+1;k<N2;k++) {
g2->x[k][c] = 0.5f * g->x[k+N2][c];
}
}
return g2;
}
grain* grain :: downsample()
{
grain *g2 = grain::create(N/2,pad);
grain *g = this;
for(int c=0;c<2;c++) {
for(int k=0;k<=N/4-1;k++)
g2->x[k][c] = g->x[k][c];
g2->x[N/4][c] = 0.5f*(g->x[N/4][c] + g->x[N-N/4][c] );
for(int k=N/4+1;k<N/2;k++)
g2->x[k][c] = g->x[k+N/2][c];
}
return g2;
}
}

View File

@ -1,37 +1,54 @@
// -*- mode: c++ -*-
#ifndef GRAIN_H
#define GRAIN_H
#include "fft.h"
#include "audio.h"
#include "sbsms.h"
namespace _sbsms_ {
enum windowType {
hann,
hannpoisson
};
class GrainAllocator;
class grain {
public:
static grain* create(int N, real pad);
static void destroy(grain *g);
static void referenced(grain *g);
static void forget(grain *g);
t_fft *x;
int N;
int h;
real pad;
int refCount;
audio *peak;
~grain();
void analyze();
void synthesize();
grain* upsample();
grain* downsample();
void downsample(grain *gdown);
audio *x;
friend class GrainAllocator;
protected:
grain(int N,real pad);
void calc_plans();
void calc_windows();
real *ww;
fftplan *fftPlan, *ifftPlan;
grain(int N, int N2);
float *w;
int N;
float synthScale;
int refCount;
fftplan fftPlan;
fftplan ifftPlan;
};
class GrainAllocator {
public:
GrainAllocator(int N, int N2, int type);
~GrainAllocator();
grain *create();
void reference(grain *g);
void forget(grain *g);
friend class grain;
friend class GrainBuf;
protected:
int N;
int N2;
int type;
float *w;
audio *W;
fftplan fftPlan;
fftplan ifftPlan;
};
}

View File

@ -1,47 +0,0 @@
#include "peak.h"
#include <stdlib.h>
#include <string.h>
namespace _sbsms_ {
PeakAllocator :: PeakAllocator()
{
size = 0;
count = 0;
peaks = NULL;
}
PeakAllocator :: ~PeakAllocator()
{
if(peaks) free(peaks);
}
peak *PeakAllocator :: create()
{
if(count >= size) {
if(size == 0)
size = 1024;
else
size *= 2;
peak *newpeaks = (peak*)malloc(size*sizeof(peak));
if(peaks) {
memcpy(newpeaks,peaks,count*sizeof(peak));
free(peaks);
}
peaks = newpeaks;
}
return peaks+(count++);
}
void PeakAllocator :: destroy(peak *p)
{
count--;
}
void PeakAllocator :: destroyAll()
{
count = 0;
}
}

View File

@ -1,41 +0,0 @@
#ifndef PEAK_H
#define PEAK_H
/*
Semantics are such that if destroy(p) or destroyAll() is called then all peaks create()'d after p are invalid. It is OK to create() a peak, destroy it before calling create() again, then create() another, or to create() a set of peaks, then destroy them ALL in any order, and repeat.
*/
#include "sbsms.h"
namespace _sbsms_ {
class peak {
public:
peak *tp;
peak *tn;
peak *tp2;
peak *tn2;
real x;
real y;
real y2;
int k;
real m;
};
class PeakAllocator {
public:
PeakAllocator();
~PeakAllocator();
peak *create();
void destroy(peak *p);
void destroyAll();
protected:
long count;
long size;
peak *peaks;
};
}
#endif

View File

@ -1,3 +1,4 @@
// -*- mode: c++ -*-
/*
** Copyright (C) 2001-2003 Erik de Castro Lopo <erikd@mega-nerd.com>
**
@ -203,10 +204,4 @@
#endif
#ifdef SBSMS_REAL_FLOAT
#define round2int(x) lrintf(x)
#else
#define round2int(x) lrint(x)
#endif
#endif

View File

@ -6,225 +6,244 @@
#include "real.h"
#include "utils.h"
#include <algorithm>
#include "buffer.h"
using namespace std;
namespace _sbsms_ {
#define SBSMS_RESAMPLE_CHUNK_SIZE 8192L
enum { resampleChunkSize = 8192 };
class ResamplerImp {
public:
ResamplerImp(SBSMSResampleCB func, void *data, SlideType slideType = SlideConstant);
~ResamplerImp();
inline long read(audio *audioOut, long frames);
inline void writingComplete();
inline void reset();
inline void init();
inline long samplesInOutput();
protected:
SBSMSFrame frame;
SampleCountType startAbs;
SampleCountType midAbs;
float midAbsf;
SampleCountType endAbs;
SampleCountType writePosAbs;
bool bInput;
SampleBuf *out;
SBSMSResampleCB cb;
void *data;
long inOffset;
SlideType slideType;
Slide *slide;
bool bWritingComplete;
};
Resampler :: Resampler(sbsms_resample_cb cb, void *data)
Resampler :: Resampler(SBSMSResampleCB cb, void *data, SlideType slideType)
{
imp = new ResamplerImp(cb,data,slideType);
}
ResamplerImp :: ResamplerImp(SBSMSResampleCB cb, void *data, SlideType slideType)
{
init();
this->cb = cb;
this->data = data;
bPull = true;
bInput = true;
this->slideType = slideType;
frame.size = 0;
}
Resampler :: Resampler(SampleBuf *in, real ratio)
{
init();
bPull = false;
this->in = in;
bInput = true;
frame.ratio0 = ratio;
frame.ratio1 = ratio;
}
void Resampler :: init()
void ResamplerImp :: init()
{
inOffset = 0;
startAbs = 0;
midAbs = 0;
endAbs = 0;
writePosAbs = 0;
midAbsf = 0.0;
midAbsf = 0.0f;
out = new SampleBuf(0);
slide = NULL;
bWritingComplete = false;
sincZeros = SBSMS_SINC_SAMPLES;
}
void Resampler :: reset()
void Resampler :: reset() { imp->reset(); }
void ResamplerImp :: reset()
{
if(slide) delete slide;
delete out;
init();
frame.size = 0;
bInput = true;
}
long Resampler :: read(audio *audioOut, long samples)
Resampler :: ~Resampler() { delete imp; }
ResamplerImp :: ~ResamplerImp()
{
if(!bPull) {
frame.in = in->getReadBuf();
frame.size = in->n_readable();
if(frame.size) bInput = true;
}
if(slide) delete slide;
delete out;
}
long nRead = out->n_readable();
void updateSlide(Slide *slide, float *f, float *scale, int *maxDist, float *ratio)
{
float stretch = slide->getStretch();
slide->step();
if(stretch <= 1.0f) {
*f = resampleSincRes;
*scale = stretch;
*maxDist = lrintf(resampleSincSamples);
} else {
*f = resampleSincRes / stretch;
*scale = 1.0f;
*maxDist = lrintf(resampleSincSamples * stretch);
}
*ratio = stretch;
}
long Resampler :: read(audio *audioOut, long samples) { return imp->read(audioOut,samples); }
long ResamplerImp :: read(audio *audioOut, long samples)
{
long nRead = out->nReadable();
while(nRead < samples && bInput) {
if(bInput && inOffset == frame.size) {
if(!bPull) {
in->advance(frame.size);
bInput = false;
cb(data,&frame);
if(frame.size) {
if(slide) delete slide;
slide = new Slide(slideType,1.0f/frame.ratio0,1.0f/frame.ratio1,frame.size);
} else {
cb(data,&frame);
if(!frame.size)
bWritingComplete = true;
bWritingComplete = true;
}
if(bWritingComplete) {
bInput = false;
out->grow(midAbs - writePosAbs);
out->writePos += midAbs - writePosAbs;
out->delay = 0;
bInput = false;
long n = (long)(midAbs - writePosAbs);
out->grow(n);
out->writePos += n;
}
inOffset = 0;
}
if(frame.size) {
real dratio = 1.0f/(real)frame.size*(frame.ratio1-frame.ratio0);
real ratio = frame.ratio0 + (real)inOffset*dratio;
real ratiorec = ratio<1.0f?1.0f:1.0f/ratio;
real f = ratiorec*SBSMS_SINC_RES;
int fi = round2int(f-0.5f);
real ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
real scale = ratio<1.0f?ratio:1.0f;
int maxDist = round2int(sincZeros*ratio-0.5f);
// absolute start position
startAbs = max((long)0,midAbs-maxDist);
// samples to advance
long advance = max((long)0,startAbs - maxDist - writePosAbs);
writePosAbs += advance;
// absolute end position
endAbs = midAbs + maxDist;
// starting position in output
int start = startAbs - writePosAbs;
assert(start>=0);
// zero point in output
int mid = midAbs - writePosAbs;
// ending position in output
int end = endAbs - writePosAbs;
// provide extra delay for variable rate ratio
out->delay = maxDist<<1;
out->writePos += advance;
if(fabs(ratio-1.0f) < 1e-6f && fabs(dratio) < 1e-8f ) {
// how far ahead to write
int nAhead = mid+frame.size;
out->N = nAhead;
out->grow(nAhead);
long nWrite = min(SBSMS_RESAMPLE_CHUNK_SIZE,frame.size-inOffset);
for(int j=0;j<nWrite;j++) {
out->buf[out->writePos+mid+j][0] += frame.in[j+inOffset][0];
out->buf[out->writePos+mid+j][1] += frame.in[j+inOffset][1];
}
inOffset += nWrite;
midAbsf += ratio*nWrite;
int nWritten = round2int(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
if(slideType == SlideIdentity) {
out->write(frame.buf,frame.size);
inOffset = frame.size;
} else {
long nWrite = min(SBSMS_RESAMPLE_CHUNK_SIZE,frame.size-inOffset);
audio *i = &(frame.in[inOffset]);
for(int j=0;j<nWrite;j++) {
// how far ahead to write
int nAhead = end;
out->N = nAhead;
out->grow(nAhead);
audio *o = &(out->buf[out->writePos+start]);
real d = (start-mid-midAbsf)*f;
int di = round2int(d-0.5f);
real df = d-di;
if(df<0.0f) {
df += 1.0f;
di--;
}
real i0 = (*i)[0];
real i1 = (*i)[1];
for(int k=start;k<end;k++) {
int k0 = (di<0)?-di:di;
int k1 = (di<0)?k0-1:k0+1;
real sinc;
if(k1>=SBSMS_SINC_SIZE) {
if(k0>=SBSMS_SINC_SIZE) {
sinc = 0.0f;
} else {
sinc = scale*sincTable[k0];
}
} else if(k0>=SBSMS_SINC_SIZE) {
sinc = scale*sincTable[k1];
} else {
sinc = scale*((1.0f-df)*sincTable[k0] + df*sincTable[k1]);
}
(*o)[0] += i0 * sinc;
(*o)[1] += i1 * sinc;
di += fi;
df += ff;
if(!(df<1.0f)) {
df -= 1.0f;
di++;
}
o++;
}
i++;
midAbsf += ratio;
if(dratio != 0.0f) {
ratio += dratio;
ratiorec = ratio<1.0f?1.0f:1.0f/ratio;
f = ratiorec*SBSMS_SINC_RES;
fi = round2int(f-0.5f);
ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
scale = ratio<1.0f?ratio:1.0f;
maxDist = round2int(sincZeros*ratio-0.5f);
}
int nWritten = round2int(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
startAbs = max((long)0,midAbs-maxDist);
endAbs = midAbs + maxDist;
start = startAbs - writePosAbs;
mid = midAbs - writePosAbs;
end = endAbs - writePosAbs;
}
inOffset += nWrite;
bool bNoSinc = false;
if(fabs(frame.ratio0-1.0f) < 1e-6f &&
fabs((float)(frame.ratio1 - frame.ratio0)/(float)frame.size) < 1e-9f) {
bNoSinc = true;
}
float f;
float scale;
int maxDist;
float ratio;
updateSlide(slide,&f,&scale,&maxDist,&ratio);
int fi = lrintf(f);
float ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
startAbs = max((SampleCountType)0,midAbs-maxDist);
long advance = max(0L,(long)(startAbs - maxDist - writePosAbs));
writePosAbs += advance;
endAbs = midAbs + maxDist;
long start = (long)(startAbs - writePosAbs);
long mid = (long)(midAbs - writePosAbs);
long end = (long)(endAbs - writePosAbs);
out->writePos += advance;
if(bNoSinc) {
int nAhead = mid+frame.size;
out->N = nAhead;
out->grow(nAhead);
long nWrite = min((long)resampleChunkSize,frame.size-inOffset);
for(int j=0;j<nWrite;j++) {
out->buf[out->writePos+mid+j][0] += frame.buf[j+inOffset][0];
out->buf[out->writePos+mid+j][1] += frame.buf[j+inOffset][1];
}
inOffset += nWrite;
midAbsf += nWrite;
int nWritten = lrintf(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
} else {
long nWrite = min((long)resampleChunkSize,frame.size-inOffset);
audio *i = &(frame.buf[inOffset]);
for(int j=0;j<nWrite;j++) {
int nAhead = end;
out->N = nAhead;
out->grow(nAhead);
audio *o = &(out->buf[out->writePos+start]);
float d = (start-mid-midAbsf)*f;
int di = lrintf(d);
float df = d-di;
if(df<0.0f) {
df += 1.0f;
di--;
}
float i0 = (*i)[0];
float i1 = (*i)[1];
for(int k=start;k<end;k++) {
int k0 = (di<0)?-di:di;
int k1 = (di<0)?k0-1:k0+1;
float sinc;
if(k1>=resampleSincSize) {
if(k0>=resampleSincSize) {
sinc = 0.0f;
} else {
sinc = scale*sincTable[k0];
}
} else if(k0>=resampleSincSize) {
sinc = scale*sincTable[k1];
} else {
sinc = scale*((1.0f-df)*sincTable[k0] + df*sincTable[k1]);
}
(*o)[0] += i0 * sinc;
(*o)[1] += i1 * sinc;
di += fi;
df += ff;
if(!(df<1.0f)) {
df -= 1.0f;
di++;
}
o++;
}
i++;
updateSlide(slide,&f,&scale,&maxDist,&ratio);
fi = lrintf(f);
ff = f - fi;
if(ff<0.0f) {
ff += 1.0f;
fi--;
}
midAbsf += ratio;
int nWritten = lrintf(midAbsf);
midAbsf -= nWritten;
midAbs += nWritten;
startAbs = max((SampleCountType)0,midAbs-maxDist);
endAbs = midAbs + maxDist;
start = (long)(startAbs - writePosAbs);
mid = (long)(midAbs - writePosAbs);
end = (long)(endAbs - writePosAbs);
}
inOffset += nWrite;
}
}
nRead = out->nReadable();
}
nRead = out->n_readable();
}
nRead = min(samples,out->n_readable());
if(nRead) {
out->read(audioOut,nRead);
out->advance(nRead);
}
return nRead;
out->read(audioOut,samples);
return samples;
}
long Resampler :: samplesInOutput()
long Resampler :: samplesInOutput() { return imp->samplesInOutput(); }
long ResamplerImp :: samplesInOutput()
{
long samplesFromBuffer = round2int(0.5f*(frame.ratio0+frame.ratio1)*(frame.size-inOffset));
return out->writePos + midAbs - writePosAbs - out->readPos + samplesFromBuffer;
long samplesFromBuffer = lrintf(0.5f*(frame.ratio0+frame.ratio1)*(frame.size-inOffset));
return (long)(out->writePos + (midAbs - writePosAbs) - out->readPos + samplesFromBuffer);
}
void Resampler :: writingComplete()
void ResamplerImp :: writingComplete()
{
bWritingComplete = true;
}
Resampler :: ~Resampler()
{
delete out;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,14 @@
#ifndef SBSMS_SINCCOEFFS_H
#define SBSMS_SINCCOEFFS_H
// -*- mode: c++ -*-
#ifndef SINCCOEFFS_H
#define SINCCOEFFS_H
#include "sbsms.h"
#define SBSMS_SINC_SIZE 5286
#ifdef SBSMS_REAL_FLOAT
#define SBSMS_SINC_RES 128.0f
#define SBSMS_SINC_SAMPLES 41.0f
#else
#define SBSMS_SINC_RES 128.0
#define SBSMS_SINC_SAMPLES 41.0
#endif
enum {
resampleSincSize = 5286,
resampleSincRes = 128,
resampleSincSamples = 41 };
namespace _sbsms_ {
real sincTable[SBSMS_SINC_SIZE] =
float sincTable[resampleSincSize] =
{
0.920381425342433f,
0.920302993473145f,

476
lib-src/sbsms/src/slide.cpp Normal file
View File

@ -0,0 +1,476 @@
#include "sbsms.h"
#include "real.h"
#include <math.h>
#include <algorithm>
using namespace std;
namespace _sbsms_ {
class SlideImp {
public:
virtual ~SlideImp() {}
virtual float getTotalStretch()=0;
virtual float getStretchedTime(float t)=0;
virtual float getRate(float t)=0;
virtual float getStretch(float t)=0;
virtual float getRate()=0;
virtual float getStretch()=0;
virtual void step()=0;
};
class IdentitySlide : public SlideImp {
public:
IdentitySlide() {
}
float getTotalStretch() {
return 1.0f;
}
float getStretchedTime(float t) {
return t;
}
float getRate(float t) {
return 1.0f;
}
float getStretch(float t) {
return 1.0f;
}
float getRate() {
return 1.0f;
}
float getStretch() {
return 1.0f;
}
void step() {
}
};
class ConstantSlide : public SlideImp {
public:
ConstantSlide(float rate) {
this->rate = rate;
}
float getTotalStretch() {
return 1.0f / rate;
}
float getStretchedTime(float t) {
return t / rate;
}
float getRate(float t) {
return rate;
}
float getStretch(float t) {
return 1.0f / rate;
}
float getRate() {
return rate;
}
float getStretch() {
return 1.0f / rate;
}
void step() {
}
protected:
float rate;
};
class LinearInputRateSlide : public SlideImp {
public:
LinearInputRateSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
if(n) {
val = rate0;
inc = (rate1 - rate0) / (double)n;
}
}
float getTotalStretch() {
return log(rate1 / rate0) / (rate1 - rate0);
}
float getStretchedTime(float t) {
float ratet = getRate(t);
return log(ratet / rate0) / (rate1 - rate0);
}
float getRate(float t) {
return rate0 + (rate1 - rate0) * t;
}
float getStretch(float t) {
return 1.0f / getRate(t);
}
float getRate() {
return (float)val;
}
float getStretch() {
return (float)(1.0 / val);
}
void step() {
val += inc;
}
protected:
float rate0, rate1;
double val, inc;
};
class LinearOutputRateSlide : public SlideImp {
public:
LinearOutputRateSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
if(n) {
val = 0.0;
inc = 1.0 / (double)n;
}
}
float getTotalStretch() {
return 2.0f / (rate0 + rate1);
}
float getStretchedTime(float t) {
return (sqrt(rate0 * rate0 + (rate1 * rate1 - rate0 * rate0) * t) - rate0) * 2.0f / (rate1 * rate1 - rate0 * rate0);
}
float getRate(float t) {
return rate0 + (sqrt(rate0 * rate0 + (rate1 * rate1 - rate0 * rate0) * t) - rate0);
}
float getStretch(float t) {
return 1.0f / getRate(t);
}
float getRate() {
return getRate((float)val);
}
float getStretch() {
return getStretch((float)val);
}
void step() {
val += inc;
}
protected:
float rate0, rate1;
double val, inc;
};
class LinearInputStretchSlide : public SlideImp {
public:
LinearInputStretchSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
if(n) {
val = 1.0 / rate0;
inc = (1.0 / rate1 - 1.0 / rate0) / (double)n;
}
}
float getTotalStretch() {
return 0.5f / rate0 + 0.5f / rate1;
}
float getStretchedTime(float t) {
return t / rate0 * (1.0f + 0.5f * t * (rate0 / rate1 - 1.0f));
}
float getRate(float t) {
return 1.0f / getStretch(t);
}
float getStretch(float t) {
return (1.0f / rate0 + (1.0f / rate1 - 1.0f / rate0) * t);
}
float getRate() {
return (float)(1.0 / val);
}
float getStretch() {
return (float)val;
}
void step() {
val += inc;
}
protected:
float rate0, rate1;
double val, inc;
};
class LinearOutputStretchSlide : public SlideImp {
public:
LinearOutputStretchSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
c0 = rate0 / rate1;
c1 = 1.0f / (rate0 * log(c0));
if(n) {
val = 0.0;
inc = 1.0 / (double)n;
}
}
float getTotalStretch() {
return c1 * (c0 - 1.0f);
}
float getStretchedTime(float t) {
return c1 * (pow(c0, t) - 1.0f);
}
float getRate(float t) {
return rate0 * pow(c0, -t);
}
float getStretch(float t) {
return pow(c0, t) / rate0;
}
float getRate() {
return getRate((float)val);
}
float getStretch() {
return getStretch((float)val);
}
void step() {
val += inc;
}
protected:
float rate0, rate1;
double val, inc;
float c0, c1;
};
class GeometricInputSlide : public SlideImp {
public:
GeometricInputSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
if(n) {
val = rate0;
inc = pow((double)rate1 / rate0, 1.0 / (double)n);
}
}
float getTotalStretch() {
return (rate1 - rate0) / (log(rate1 / rate0) * (rate0 * rate1));
}
float getStretchedTime(float t) {
return (float)(pow(rate0 / rate1, t) - 1.0) / (rate0 * log(rate0 / rate1));
}
float getRate(float t) {
return rate0 * pow(rate1 / rate0, t);
}
float getStretch(float t) {
return 1.0f / getRate(t);
}
float getRate() {
return (float)val;
}
float getStretch() {
return (float)(1.0 / val);
}
void step() {
val *= inc;
}
protected:
float rate0, rate1;
double val, inc;
};
class GeometricOutputSlide : public SlideImp {
public:
GeometricOutputSlide(float rate0, float rate1, const SampleCountType &n) {
this->rate0 = rate0;
this->rate1 = rate1;
log10 = log(rate1 / rate0);
r10 = rate1 - rate0;
totalStretch = getTotalStretch();
if(n) {
val = 0.0;
inc = 1.0 / (double)n;
}
}
float getTotalStretch() {
return log(rate1 / rate0) / (rate1 - rate0);
}
float getStretchedTime(float t) {
return log(r10 / rate0 * t + 1.0f) / r10;
}
float getRate(float t) {
float t1 = getStretchedTime(t) / totalStretch;
return rate0 * pow(rate1 / rate0, t1);
}
float getStretch(float t) {
return 1.0f / getRate(t);
}
float getRate() {
return getRate((float)val);
}
float getStretch() {
return getStretch((float)val);
}
void step() {
val += inc;
}
protected:
float rate0, rate1;
float log10, r10, totalStretch;
double val, inc;
};
Slide :: Slide(SlideType slideType, float rate0, float rate1, const SampleCountType &n)
{
if(slideType == SlideIdentity) {
imp = new IdentitySlide();
} else if(slideType == SlideConstant || rate0 == rate1) {
imp = new ConstantSlide(rate0);
} else if(slideType == SlideLinearInputRate) {
imp = new LinearInputRateSlide(rate0,rate1,n);
} else if(slideType == SlideLinearOutputRate) {
imp = new LinearOutputRateSlide(rate0,rate1,n);
} else if(slideType == SlideLinearInputStretch) {
imp = new LinearInputStretchSlide(rate0,rate1,n);
} else if(slideType == SlideLinearOutputStretch) {
imp = new LinearOutputStretchSlide(rate0,rate1,n);
} else if(slideType == SlideGeometricInput) {
imp = new GeometricInputSlide(rate0,rate1,n);
} else if(slideType == SlideGeometricOutput) {
imp = new GeometricOutputSlide(rate0,rate1,n);
}
}
Slide :: ~Slide()
{
delete imp;
}
float Slide :: getTotalStretch()
{
return imp->getTotalStretch();
}
float Slide :: getRate(float t)
{
if(t > 1.0f) t = 1.0f;
return imp->getRate(t);
}
float Slide :: getStretch(float t)
{
if(t > 1.0f) t = 1.0f;
return imp->getStretch(t);
}
float Slide :: getStretchedTime(float t)
{
if(t > 1.0f) t = 1.0f;
return imp->getStretchedTime(t);
}
float Slide :: getRate()
{
return imp->getRate();
}
float Slide :: getStretch()
{
return imp->getStretch();
}
void Slide :: step()
{
imp->step();
}
class SBSMSInterfaceSlidingImp {
public:
friend class SBSMSInterfaceSliding;
SBSMSInterfaceSlidingImp(Slide *rateSlide,
Slide *pitchSlide,
bool bPitchReferenceInput,
const SampleCountType &samplesToInput,
long preSamples,
SBSMSQuality *quality);
~SBSMSInterfaceSlidingImp() {}
inline float getStretch(float t);
inline float getPitch(float t);
inline long getPresamples();
SampleCountType getSamplesToInput();
SampleCountType getSamplesToOutput();
protected:
Slide *stretchSlide;
Slide *pitchSlide;
bool bPitchReferenceInput;
float totalStretch;
float stretchScale;
long preSamples;
SampleCountType samplesToInput;
SampleCountType samplesToOutput;
};
SBSMSInterfaceSlidingImp :: SBSMSInterfaceSlidingImp(Slide *stretchSlide,
Slide *pitchSlide,
bool bPitchReferenceInput,
const SampleCountType &samplesToInput,
long preSamples,
SBSMSQuality *quality)
{
this->stretchSlide = stretchSlide;
this->pitchSlide = pitchSlide;
this->bPitchReferenceInput = bPitchReferenceInput;
this->samplesToInput = samplesToInput;
this->preSamples = preSamples;
this->totalStretch = stretchSlide->getTotalStretch();
this->samplesToOutput = (SampleCountType)((float)samplesToInput * totalStretch);
stretchScale = 1.0f;
if(quality) {
SampleCountType samplesIn = 0;
SampleCountType samplesOut = 0;
float outFrameSizefloat = 0.0f;
float stretch = 1.0f;
int inFrameSize = quality->getFrameSize();
while(samplesIn < samplesToInput) {
float t = (float)samplesIn / (float)samplesToInput;
stretch = stretchSlide->getStretch(t);
outFrameSizefloat += stretch * inFrameSize;
int outFrameSize = (int) outFrameSizefloat;
outFrameSizefloat -= (float) outFrameSize;
samplesIn += inFrameSize;
samplesOut += outFrameSize;
}
SampleCountType samplesOutputed = samplesOut - lrintf(stretch * (samplesIn - samplesToInput));
stretchScale = (float)samplesToOutput / (float)samplesOutputed;
}
}
float SBSMSInterfaceSliding :: getStretch(float t) { return imp->getStretch(t); }
float SBSMSInterfaceSlidingImp :: getStretch(float t)
{
return stretchScale * stretchSlide->getStretch(t);
}
float SBSMSInterfaceSliding :: getPitch(float t) { return imp->getPitch(t); }
float SBSMSInterfaceSlidingImp :: getPitch(float t)
{
if(bPitchReferenceInput) return pitchSlide->getRate(t);
else return pitchSlide->getRate(min(1.0f,stretchSlide->getStretchedTime(t) / totalStretch));
}
long SBSMSInterfaceSliding :: getPresamples() { return imp->getPresamples(); }
long SBSMSInterfaceSlidingImp :: getPresamples()
{
return preSamples;
}
SampleCountType SBSMSInterfaceSliding :: getSamplesToInput() { return imp->getSamplesToInput(); }
SampleCountType SBSMSInterfaceSlidingImp :: getSamplesToInput()
{
return samplesToInput;
}
SampleCountType SBSMSInterfaceSliding :: getSamplesToOutput() { return imp->getSamplesToOutput(); }
SampleCountType SBSMSInterfaceSlidingImp :: getSamplesToOutput()
{
return samplesToOutput;
}
SBSMSInterfaceSliding :: SBSMSInterfaceSliding(Slide *stretchSlide,
Slide *pitchSlide,
bool bPitchReferenceInput,
const SampleCountType &samplesToInput,
long preSamples,
SBSMSQuality *quality)
{
imp = new SBSMSInterfaceSlidingImp(stretchSlide, pitchSlide, bPitchReferenceInput,
samplesToInput, preSamples, quality);
}
SBSMSInterfaceSliding :: ~SBSMSInterfaceSliding()
{
delete imp;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,141 +1,196 @@
// -*- mode: c++ -*-
#ifndef SMS_H
#define SMS_H
#include "track.h"
#include "grain.h"
#include "buffer.h"
#include "peak.h"
#include "sbsms.h"
#include "config.h"
#ifdef MULTITHREADED
#include "pthread.h"
#endif
#include "sbsms.h"
#include "track.h"
#include "grain.h"
#include "buffer.h"
#include <queue>
#include <list>
using namespace std;
namespace _sbsms_ {
class renderer;
class sms : public SampleBufBase {
friend class renderer;
enum {
minTrial2Band = 1,
minTrial1Band = 2
};
class SynthRenderer : public SBSMSRenderer, public SampleBufBase {
public:
sms(int N, unsigned short M, unsigned short M_MAX, int res, int latency, real p, real q, real pad, int Nlo, int channels, TrackAllocator *ta, PeakAllocator *pa);
void reset();
void readTrackPointsFromFile(FILE *fp);
int writeTrackPointsToFile(FILE *fp);
void setH(unsigned short h);
long addTrackPoints(grain *g0, grain *g1, grain *g2);
long assignTrackPoints(long offset, sms *hi, sms *lo, int c);
long startNewTracks(long offset, int c);
void markDuplicates(long offset, sms *hi, sms *lo, int c);
bool connectTrackPoints(trackpoint *tp0, trackpoint *tp1, sms *hi, sms *lo, real dtlo, int c);
bool adoptTrack(track *precursor, sms *lender, trackpoint *tp, real m, real dt, int c);
void synthTracks(real a, real f0, real f1);
void advanceTrackPoints(int c);
long nTrackPoints();
SynthRenderer(int channels, int h);
~SynthRenderer();
void startTime(int c, const TimeType &time, int n);
void render(int c, SBSMSTrack *t);
void endTime(int c);
long read(audio *out, long n);
long n_readable();
void advance(long n);
void zeroPad(long n);
void addTrack(int c, track *t);
~sms();
bool bPhaseLock;
int res;
int N;
unsigned short M;
real m;
int Nover2;
RingBuffer<unsigned short> hSynth;
real h2cum;
long samplePos;
TrackPointListBuffer* trackPointListBuffer[2];
#ifdef MULTITHREADED
pthread_mutex_t dataMutex;
pthread_mutex_t tplbMutex[2];
pthread_mutex_t bufferMutex;
pthread_mutex_t trackMutex[2];
#endif
protected:
unsigned short encodeReal(real x, real min, real max);
float decodeReal(unsigned short x, real min, real max);
unsigned short encodeRealLog(real x);
float decodeRealLog(unsigned short x);
bool terminal;
void markDuplicatesLo(long offset, sms *lo, long offsetlo, int c);
long assignTrackPoints_(long offset, sms *hi, sms *lo, real dtlo, long offsetlo, int c);
void deleteTrackPoint(trackpoint *tp);
void adjustPeaks(list<peak*> &peaks,
real *mag0,
real *mag1,
real *mag2,
real *dec,
int peakWidth);
long assignTrackPoints(long offset, sms *hi, sms *lo, real dtlo, long offsetlo, int c);
bool contTrack(track *t, trackpoint *tp, int c);
void extractTrackPoints(grain *g, real *mag0, real *mag1, real *mag2, long currtime, TrackPointListBuffer *tplb, unsigned short h1, int c);
bool nearestTrackPoint(tplist *tpl, trackpoint *tp0, real m0, real m1, real dt, tplist::iterator *minpos, real *minFx, real maxMerit2, real maxDF2);
int prune(trackpoint *tp);
real merit(trackpoint *tp0, trackpoint *tp1, real m0, real m1, real dt, real dMCoeff, real *df, real maxDF2);
void calcmags(real *mag, grain *g, real q);
peak *makePeak(real *mag, real *mag2, int k);
TrackAllocator *ta;
PeakAllocator *pa;
char *pData;
int datasize;
int channels;
real p,q;
int peakWidth;
int maxPrunes;
real peakThresh;
real startThresh;
real maxMerit2;
real maxDF2;
real dMCoeff;
real maxMerit2Match;
real maxDF2Match;
real dMCoeffMatch;
int minNpts;
real maxdBIncr;
real maxdBIncrStitch;
real maxFMatch;
real minFMatch;
float *synthBuf[2];
int synthBufLength[2];
ArrayRingBuffer<float> *sines[2];
TimeType time[2];
int n[2];
#ifdef MULTITHREADED
pthread_mutex_t bufferMutex;
#endif
};
class SMS {
public:
SMS(SMS *lo, int N, int band, int bandMax, int h, int res, int N0, int N1, int N2, int channels, audio *peak2);
~SMS();
void render(int c, list<SBSMSRenderer*> &renderers);
void add(grain *g0, grain *g1, grain *g2, int c);
void assignStart(long offset, int c);
void assignInit(long offset, int c);
void assignFind(long offset, int c);
bool assignConnect(long offset, int c, bool bLastDitch);
void start(long offset, int c);
void splitMerge(int c);
void mark(long offset, int c);
void advance(int c);
void trial2(int c);
void trial2Start(int c);
void trial2End(int c);
void adjust2();
void trial1(int c);
void trial1Start(int c);
void trial1End(int c);
void adjust1(float stretch, float pitch0, float pitch1);
void adjustInit(ArrayRingBuffer<float> **trialRingBuf,
GrainBuf *trialGrainBuf);
void adjust(GrainBuf *trialGrainBuf,
queue<float*> *magQueue,
int minCutSep,
float **_mag1,
float **_dmag1,
audio **x1,
const TimeType &time,
Slice **slice);
void prepad1(audio *buf, long n);
void prepad0(audio *buf, long n);
int getTrial2Latency();
protected:
void connect(TrackPoint *tp0, TrackPoint *tp1, int ilo, int c);
void mark(long offset, long offsetlo, int c);
TrackPoint *nearestForward(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF2, float dMCoeff2, float dNCoeff2 = 0.0f);
TrackPoint *nearestReverse(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF2, float dMCoeff2, float dNCoeff2 = 0.0f);
TrackPoint *nearestForward2(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF2, float dMCoeff2, float dNCoeff2 = 0.0f);
TrackPoint *nearestReverse2(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF2, float dMCoeff2, float dNCoeff2 = 0.0f);
float interp2(int k, int ko1, float kf);
float findExtremum(float *mag, float *mag2, int k, float *y);
void calcmags(float *mag, audio *x);
int findCut(float *dmag, int k, int maxK);
Track *createTrack(int c, TrackPoint *tp, const TimeType &time, bool bStitch);
void returnTrackIndex(int c, Track *t);
list<TrackPoint*> ended[2];
list<TrackPoint*> started[2];
int minTrackSize;
int peakWidth0;
int peakWidth1;
int peakWidth2;
int minCutSep1;
int minCutSep2;
int minK;
int maxK;
float peakThresh;
float maxCost2;
float maxDF;
float dMCoeff2;
float dNCoeff2;
float maxDFSplitMerge;
float maxCost2SplitMerge;
float dMCoeff2SplitMerge;
float maxCost2Match;
float maxDFMatch;
float dMCoeff2Match;
float maxCost2Stereo;
float maxDFStereo;
float dMCoeff2Stereo;
float maxFMatchM;
float minFMatchL;
float minFLo;
float maxFHi;
float minFMid;
float maxFMid;
int kStart;
int kEnd;
real mNorm;
real minPeakTopRatio;
real localFavorRatio;
real maxDecRatio;
list<track*> **trax;
long currtime;
long assigntime[2];
long marktime[2];
long synthtime;
SampleBuf *sines2, *outMixer;
grain* x0[2];
grain* x1[2];
grain* x2[2];
void c2evenodd(grain *g, grain *, grain *);
real* dec;
real* dec2;
real* mag0[2];
real* mag1[2];
real* mag2[2];
real *peak1;
bool bPeakSet;
real sqrtmagmax;
real magmax;
int kLo;
int kHi;
float mNorm;
float localFavorRatio;
queue<Slice*> adjust2SliceQueue[2];
queue<Slice*> adjust1SliceQueue[2];
RingBuffer<Slice*> sliceBuffer[2];
Slice* sliceM0[2];
Slice* sliceL0[2];
Slice* sliceH0[2];
Slice* sliceM1[2];
Slice* sliceL1[2];
Slice* sliceM2[2];
Slice* sliceH1[2];
audio* x10[2];
audio* x11[2];
float* dmag1[2];
float* mag11[2];
audio* x00[2];
audio* x01[2];
float* dmag0[2];
float* mag01[2];
float *mag2[2];
audio* x2[2];
float* dec2[2];
float *peak20;
float *peak2N;
int N;
int Nover2;
SMS *lo;
SMS *hi;
queue<TrackIndexType> trackIndex[2];
queue<float*> mag1Queue[2];
queue<float*> mag0Queue[2];
float *trial2Buf[2];
ArrayRingBuffer<float> *trial2RingBuf[2];
GrainBuf *trial2GrainBuf;
float *trial1Buf[2];
ArrayRingBuffer<float> *trial1RingBuf[2];
GrainBuf *trial1GrainBuf;
list<Track*> assignTracks[2];
list<Track*> renderTracks[2];
TimeType addtime[2];
TimeType assigntime[2];
TimeType trial2time[2];
TimeType adjust2time;
TimeType trial1time[2];
TimeType adjust1time;
TimeType synthtime[2];
queue<int> nRender[2];
double h2cum;
int channels;
long res;
long resMask;
int h;
float M;
double h1;
int band;
#ifdef MULTITHREADED
pthread_mutex_t sliceMutex[2];
pthread_mutex_t magMutex[2];
pthread_mutex_t renderMutex[2];
pthread_mutex_t trial2Mutex[2];
pthread_mutex_t trial1Mutex[2];
pthread_mutex_t trackMutex[2];
#endif
bool bAssignDone[2];
};
}

32
lib-src/sbsms/src/sse.h Normal file
View File

@ -0,0 +1,32 @@
// -*- mode: c++ -*-
#ifndef SSE_H
#define SSE_H
#include "config.h"
#ifdef ENABLE_SSE
#include <xmmintrin.h>
namespace _sbsms_ {
typedef __m128 simd_vector;
#define LOAD(p) _mm_loadu_ps((float*)(p))
#define STORE(v,p) _mm_storeu_ps((float*)(p),v)
#define LOAD16(p) _mm_load_ps((float*)(p))
#define STORE16(v,p) _mm_store_ps((float*)(p),v)
#define LOADL(v,p) _mm_loadl_pi(v,(const __m64*)(p))
#define LOADH(v,p) _mm_loadh_pi(v,(const __m64*)(p))
#define STOREL(v,p) _mm_storel_pi((__m64 *)(p), v)
#define STOREH(v,p) _mm_storeh_pi((__m64 *)(p), v)
#define VADD(v1,v2) _mm_add_ps(v1,v2)
#define VSUB(v1,v2) _mm_sub_ps(v1,v2)
#define VMUL(v1,v2) _mm_mul_ps(v1,v2)
#define SHUFFLE(a,b,w,x,y,z) _mm_shuffle_ps(a,b,_MM_SHUFFLE(z,y,x,w))
#define SET(f) _mm_set1_ps(f)
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
// -*- mode: c++ -*-
#ifndef SUBBAND_H
#define SUBBAND_H
#include "real.h"
#include "buffer.h"
#include "audio.h"
#include "sms.h"
#include <stdio.h>
#include "config.h"
@ -13,164 +13,172 @@
namespace _sbsms_ {
class renderer;
enum {
NDownSample = 256,
SDownSample = 4,
subBufSize = 512,
hSub = NDownSample/(2*SDownSample)
};
class subband {
friend class renderer;
class SubBand {
public:
subband(subband *parent, unsigned short M, int channels, sbsms_quality *quality, int latency, bool bPreAnalysis, TrackAllocator *ta, PeakAllocator *pa);
~subband();
SubBand(SubBand *parent, int band, int channels, SBSMSQuality *quality, bool bSynthesize);
~SubBand();
long write(audio *buf, long n, real a, real ratio);
void process();
long read(audio *buf, real *ratio0, real *ratio1);
long n_readable();
bool isframe_readable();
void writingComplete();
long readFromFile(FILE *fp, real a, real ratio);
long synth();
long getFramesWrittenToFile();
long writeToFile(FILE *fp);
void init();
void reset();
void seek(long framePos);
long getSamplesQueued();
long getFramesQueued();
long getFramesAtFront();
long getFramesAtBack();
long getLastInputFrameSize();
long getFramePos();
void write_(audio *buf, long n, real a, real ratio);
long write(audio *buf, long n, float stretch, float pitch);
long read(audio *buf, long n);
long getInputFrameSize();
void writeFramePositionsToFile(FILE *fp);
long addInit(bool);
void addTrackPoints();
long markInit(bool, int c);
void markDuplicates(int c);
long assignInit(bool,int c);
long assignTrackPoints(int c);
void startNewTracks(int c);
void advanceTrackPoints(int c);
long synthInit(bool);
void synthTracks();
long readInit(bool);
long writeTracksToFile(FILE *fp);
void readTrackPointsFromFile(FILE *fp);
long writeTrackPointsToFile(FILE *fp);
void stepAddFrame();
void stepMarkFrame(int c);
void stepAssignFrame(int c);
void stepSynthFrame();
bool writeInit();
long analyzeInit(int,bool,long n=0);
long extractInit(int,bool);
long markInit(int,bool);
long assignInit(int,bool);
long trial2Init(int,bool);
long adjust2Init(bool);
long trial1Init(int,bool);
long adjust1Init(bool);
long renderInit(int,bool);
long writeFromFileInit(int,bool);
long readInit();
void analyze(int);
void extract(int);
void mark(int);
void assign(int);
void trial2(int);
void trial2Start(int);
void trial2Trial(int);
void trial2End(int);
void adjust2();
void trial1(int);
void trial1Start(int);
void trial1Trial(int);
void trial1End(int);
void adjust1();
void advance(int);
void render(int);
void assignStart(int c);
void assignInit(int c);
void assignFind(int c);
bool assignConnect(int c);
void assignStep(int c);
void splitMerge(int c);
void addRenderer(SBSMSRenderer *);
void removeRenderer(SBSMSRenderer *);
long renderSynchronous();
void renderComplete(const SampleCountType &samples);
void process(bool);
void stepAnalyzeFrame(int);
void stepExtractFrame(int);
void stepMarkFrame(int);
void stepAssignFrame(int);
void stepTrial2Frame(int);
void stepAdjust2Frame();
void stepTrial1Frame(int);
void stepAdjust1Frame();
void stepRenderFrame(int);
void stepReadFrame();
void readSubSamples();
void setA(real a);
void setAMod(real a);
void setAForH(real a);
void setH(real ratio);
void setF(real f);
void setFrameSize(int inputSize, real a, real ratio);
void setRatio(real ratio);
void setFramesInFile(long frames);
long zeroPad();
long zeroPad_();
long preAnalyze(audio *buf, long n, real a, real ratio);
void preAnalyzeComplete();
FILE *fp;
long getFramesAssigned();
long getFramesMarked();
bool isWriteReady();
bool isAddReady();
bool isMarkReady();
bool isAssignReady();
bool isSynthReady();
#ifdef MULTITHREADED
pthread_mutex_t dataMutex;
pthread_mutex_t bufferMutex;
pthread_mutex_t grainMutex[3];
#endif
long nLatency;
long nLatencyOriginal;
friend class SBSMSImp;
protected:
long read(audio *buf, long n);
void calculateA(long kstart, long kend);
real calculateOnset(grain *g1, grain *g2);
void resetNoRecurse();
long getFramesAtFront(int);
void readSubSamples();
void setStretch(float stretch);
void setPitch(float pitch);
TrackAllocator *ta;
PeakAllocator *pa;
RingBuffer<real> aPreAnalysis;
RingBuffer<real> aMod;
RingBuffer<real> aSynth;
RingBuffer<real> aForH;
RingBuffer<real> fSynth;
RingBuffer<int> inputFrameSize;
int nMarkLatency;
int nAssignLatency;
int nTrial2Latency;
int nAdjust2Latency;
int nTrial1Latency;
int nAdjust1Latency;
int nRenderLatency;
int nWriteSlack;
int nExtractSlack;
int nAnalyzeSlack;
int nMarkSlack;
int nAssignSlack;
int nTrial2Slack;
int nAdjust2Slack;
int nTrial1Slack;
int nAdjust1Slack;
int nRenderSlack;
list<SBSMSRenderer*> renderers;
RingBuffer<float> stretchRender;
RingBuffer<float> pitchRender;
int inputFrameSize;
RingBuffer<int> outputFrameSize;
RingBuffer<real> frameRatio;
RingBuffer<int> frameBytes;
RingBuffer<real> onset;
grain *gPrev;
real getOnset(long k);
int lastInputFrameSize;
int lastOutputFrameSize;
real samplesQueued;
real lastFrameA;
real lastFrameRatio;
real totalSizef;
bool bPreAnalyze;
sbsms_quality *quality;
float totalSizef;
SBSMSQuality *quality;
int channels;
int N;
int h;
unsigned short M;
int s;
int res;
int nGrainsPerFrame;
int resTotal;
long nDropped;
long nToDrop;
int band;
long nReadFromOutputFrame;
long nToWriteForGrain;
long res;
long resMask;
long nGrainsPerFrame;
long nToDrop0;
long nToDrop1;
long nToDrop2;
long nToPrepad1;
long nToPrepad0;
bool bSynthesize;
long nTrackPointsToAdd;
long nTrackPointsToMark[2];
long nTrackPointsToAssign[2];
long nTrackPointsToAdvance[2];
long nTrackPointsToSynth;
long nGrainsToAnalyze[3];
long nGrainsToExtract[2];
long nGrainsToMark[2];
long nGrainsToAssign[2];
long nGrainsToAdvance[2];
long nGrainsToTrial2[2];
long nGrainsToAdjust2;
long nGrainsToTrial1[2];
long nGrainsToAdjust1;
long nGrainsToRender[2];
long nGrainsWritten;
long nGrainsMarked[2];
long nGrainsAssigned[2];
long nGrainsTrialed2[2];
long nGrainsAdjusted2;
long nGrainsTrialed1[2];
long nGrainsAdjusted1;
long nGrainsAdvanced[2];
long nGrainsRendered[2];
long nGrainsRead;
long nTrackPointsMarked[2];
long nTrackPointsAssigned[2];
long nTrackPointsStarted[2];
long nTrackPointsAdvanced[2];
long nTrackPointsSynthed;
long nTrackPointsRead;
long nFramesSkipped;
long nFramesWritten;
long nFramesAdded;
long nFramesAnalyzed[3];
long nFramesExtracted[2];
long nFramesMarked[2];
long nFramesAssigned[2];
long nFramesTrialed2[2];
long nFramesAdjusted2;
long nFramesTrialed1[2];
long nFramesAdjusted1;
long nFramesRendered[2];
long nFramesRead;
long nFramesSynthed;
long nFramesInFile;
long nTrackPointsWritten;
bool bWritingComplete;
subband *parent;
subband *sub;
GrainBuf *in0,*in1,*in2;
SubBand *parent;
SubBand *sub;
SampleBufBase *outMixer;
sms *smser;
SampleBuf *subIn;
SampleBuf *subOut;
GrainBuf *in;
GrainBuf *inPre;
grain *x1[2];
grain *x2[2];
SynthRenderer *synthRenderer;
SMS *sms;
SampleBuf *samplesSubIn;
SampleBuf *samplesSubOut;
GrainBuf *grains[3];
GrainBuf *analyzedGrains[3][2];
GrainBuf *grainsIn;
GrainAllocator *downSampledGrainAllocator;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,309 +1,341 @@
#include "track.h"
#include <math.h>
#include "utils.h"
#include "real.h"
#include "sbsms.h"
#include "sms.h"
#include <vector>
#include "dBTable.h"
#include "synthTable.h"
#include "utils.h"
#include <algorithm>
using namespace std;
namespace _sbsms_ {
#define SBSMS_TRACK_BLOCK 2048
TrackAllocator :: TrackAllocator(bool bManageIndex)
Track :: Track(float h, TrackIndexType index, TrackPoint *p, const TimeType &time, bool bStitch)
{
this-> bManageIndex = bManageIndex;
}
TrackAllocator :: TrackAllocator(bool bManageIndex, unsigned short maxtrackindex)
{
this-> bManageIndex = bManageIndex;
gTrack.resize(maxtrackindex);
init();
}
TrackAllocator :: ~TrackAllocator()
{
}
void TrackAllocator :: init()
{
for(unsigned short k=0;k<gTrack.size();k++)
gTrack[k] = NULL;
while(!gTrackIndex.empty())
gTrackIndex.pop();
#ifdef MULTITHREADED
pthread_mutex_init(&taMutex,NULL);
#endif
}
track *TrackAllocator :: getTrack(unsigned short index)
{
return gTrack[index];
}
int TrackAllocator :: size()
{
return gTrack.size();
}
track *TrackAllocator :: create(track *precursor, sms *owner, int res, unsigned short index)
{
track *t = new track(precursor,owner,res);
t->index = index;
gTrack[index] = t;
return t;
}
track *TrackAllocator :: create(track *precursor, sms *owner, int res)
{
#ifdef MULTITHREADED
pthread_mutex_lock(&taMutex);
#endif
if(gTrackIndex.empty()) {
unsigned short n = gTrack.size();
gTrack.resize(n+SBSMS_TRACK_BLOCK);
for(int k=n+SBSMS_TRACK_BLOCK-1;k>=n;k--) {
gTrackIndex.push(k);
gTrack[k] = NULL;
}
}
unsigned short index = gTrackIndex.top();
gTrackIndex.pop();
#ifdef MULTITHREADED
pthread_mutex_unlock(&taMutex);
#endif
return create(precursor, owner, res, index);
}
void TrackAllocator :: destroy(track *t)
{
#ifdef MULTITHREADED
pthread_mutex_lock(&taMutex);
#endif
gTrack[t->index] = NULL;
if(bManageIndex)
gTrackIndex.push(t->index);
delete t;
#ifdef MULTITHREADED
pthread_mutex_unlock(&taMutex);
#endif
}
track :: track(track *precursor, sms *owner, int res)
{
this->owner = owner;
this->res = res;
this->descendant = NULL;
this->precursor = precursor;
this->end = LONG_MAX;
this->rise = 0.3f;
this->fall = 0.5f;
tailEnd = 0;
tailStart = 0;
m_p = 0.0;
currtime = 0;
}
void track :: endTrack(bool bTail)
{
end = back()->time;
if(bTail) {
this->fall = min(1.5f,.25f + back()->y / point[point.size()-2]->y);
tailEnd = 1;
end++;
trackpoint *f = new trackpoint(back());
f->time = back()->time + 1;
point.push_back(f);
}
}
void track :: synth(SampleBuf *out,
long writePos,
int c,
long synthtime,
int steps,
real fScale0,
real fScale1,
real mScale) {
if(point.size()==0) return;
long k = synthtime - start;
if(k>=(long)point.size()-1) return;
currtime = synthtime;
if(k<0) return;
int k1 = k + 1;
tpoint *tp0 = point[k];
tpoint *tp1 = point[k1];
real w0 = tp0->f;
real w1 = tp1->f;
real ph0 = tp0->ph;
real ph1 = tp1->ph;
real h = tp0->h;
real dp = ph1 - ph0;
if(dp>PI) dp-=TWOPI;
else if(dp<-PI) dp+=TWOPI;
real dp0 = 0.5f*h*(w0 + w1);
real dw = canon(dp - dp0)/h;
if(k==0) {
if(precursor) {
m_p = precursor->m_pDescendant;
} else {
dw = 0;
}
}
real dt = (real)steps;
w0 = (w0+dw);
w1 = (w1+dw);
w0 = w0*fScale0;
w1 = w1*fScale1;
dp = dt*0.5f*(w0 + w1);
real b = (w1 - w0)/(2.0f*dt);
bool bEnd = (k1==(long)point.size()-1);
bool bStart = (k==0);
if(bStart && tailStart) {
if(w0 < PI && w0 > -PI) {
real ph = m_p;
int rise = round2int(this->rise * (real)steps);
real dm = mScale*tp1->y/(real)rise;
real m = mScale*tp1->y - dm;
for(int i=steps-1;i>=steps-rise+1;i--) {
ph -= w0;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
out->buf[writePos+i][c] += m * COS(ph);
m -= dm;
}
}
} else if(bEnd && tailEnd) {
if(w0 < PI && w0 > -PI) {
real ph = m_p;
int fall = round2int(this->fall * (real)steps);
real dm = mScale*tp0->y/(real)fall;
real m = mScale*tp0->y;
for(int i=0;i<fall;i++) {
out->buf[writePos+i][c] += m * COS(ph);
ph += w0;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
m -= dm;
}
}
} else {
real m = mScale*tp0->y;
real dm = mScale*(tp1->y0 - tp0->y)/dt;
real ph = m_p;
real b2tt1 = b;
real b2 = 2.0f*b;
real dph;
audio *o = &(out->buf[writePos]);
for(int i=0;i<steps;i++) {
dph = w0 + b2tt1;
if(dph < PI && dph > -PI) (*o)[c] += m * COS(ph);
ph += dph;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
b2tt1 += b2;
m += dm;
o++;
}
}
if(bEnd) {
if(descendant && descendant->back()->M < tp0->M) {
m_pDescendant = canon(m_p + dp/dt*(real)(descendant->owner->samplePos - owner->samplePos));
}
} else if(bStart && tailStart) {
this->h = h;
jumpThresh2 = 1.0e-5f * h;
this->index = index;
bEnd = false;
bEnded = false;
bRender = false;
bSplit = false;
bMerge = false;
first = time;
start = time;
if(bStitch) {
this->bStitch = true;
} else {
m_p = canon(m_p + dp);
if(descendant && descendant->back()->M > tp0->M && (k1+res==(long)point.size()-1)) {
m_pDescendant = canon(m_p + dp/dt*(real)(descendant->owner->samplePos - (owner->samplePos+steps)));
this->bStitch = false;
if(start > 0) {
start--;
}
}
point.push_back(p);
p->owner = this;
p->refCount++;
end = time;
last = time;
}
Track :: ~Track() {
for(vector<TrackPoint*>::iterator i = point.begin();
i != point.end();
++i) {
TrackPoint *tp = (*i);
if(tp) tp->destroy();
}
}
TrackIndexType Track :: getIndex()
{
return index;
}
bool Track :: isFirst(const TimeType &time)
{
return (time == first);
}
bool Track :: isLast(const TimeType &time)
{
return (time == last);
}
TimeType Track :: size()
{
return point.size();
}
TrackPoint *Track :: back()
{
return point.back();
}
TrackPoint *Track :: getTrackPoint(const TimeType &time)
{
return point[time - first];
}
SBSMSTrackPoint *Track :: getSBSMSTrackPoint(const TimeType &time)
{
return getTrackPoint(time);
}
bool Track :: jump(TrackPoint *tp0, TrackPoint *tp1)
{
if(tp1->m > tp0->m) {
float cost = 1.0e-4f * dBApprox(tp0->m,tp1->m);
return (cost > jumpThresh2);
} else {
return false;
}
}
TrackPoint *Track :: updateFPH(const TimeType &time, int mode, int n, float f0, float f1)
{
if(time == start && time < first) {
TrackPoint *tp1 = getTrackPoint(time+1);
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * tp1->f));
tp1->fSynth0 = tp1->fSynth1;
tp1->phSynth = tp1->ph;
if(mode == synthModeOutput && tp1->dupStereo) {
return tp1;
}
} else if(time == last) {
if(last < end) {
TrackPoint *tp0 = getTrackPoint(time);
tp0->fSynth0 = tp0->fSynth1;
}
} else {
TrackPoint *tp0 = getTrackPoint(time);
TrackPoint *tp1 = getTrackPoint(time+1);
if(mode == synthModeOutput) {
if(tp0->dupStereo && tp1->dupStereo && tp0->dupStereo->owner == tp1->dupStereo->owner) {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
float dpStereo = tp1->dupStereo->ph - tp0->dupStereo->ph;
float dp0Stereo = 0.5f*h*(tp0->dupStereo->f + tp1->dupStereo->f);
float dwStereo = canonPI(dpStereo - dp0Stereo)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
dwStereo = 0;
} else if(dwStereo > .0013f * (tp0->dupStereo->f + tp1->dupStereo->f)) {
dwStereo = 0;
}
float w0 = 0.5f * (tp0->f + tp0->dupStereo->f + dw + dwStereo);
float w1 = 0.5f * (tp1->f + tp1->dupStereo->f + dw + dwStereo);
float dwSynth = 0.5f * canonPI(dp - dpStereo) / n;
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (w0 + dwSynth)));
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (w1 + dwSynth)));
}
} else {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
}
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (tp0->f + dw)));
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (tp1->f + dw)));
}
}
if(!(tp0->bSplit || tp0->bMerge || tp1->bSplit || tp1->bMerge) && jump(tp0,tp1)) {
tp1->bJump = true;
if(tp0->dupStereo && tp1->dupStereo) {
if(tp0->dupStereo->owner == tp1->dupStereo->owner) {
tp1->bSyncStereo = !jump(tp0->dupStereo,tp1->dupStereo);
}
}
}
if(!tp0->bSplit) {
if(tp0->bJump) {
if(tp0->bSyncStereo) {
tp0->phSynth = canon2PI(tp0->dupStereo->phSynth + tp0->ph - tp0->dupStereo->ph);
} else {
tp0->phSynth = tp0->ph;
}
}
}
if(!(bMerge && time + 1 == last)) {
tp1->phSynth = canon2PI(tp0->phSynth + 0.5f * (tp0->fSynth0 + tp1->fSynth1) * n);
}
} else {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
}
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (tp0->f + dw)));
tp0->phSynth = tp0->ph;
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (tp1->f + dw)));
tp1->phSynth = tp1->ph;
}
}
}
return NULL;
}
void Track :: updateM(const TimeType &time, int mode)
{
if(mode == synthModeTrial2) {
if(time == first && time == start) {
TrackPoint *tp0 = getTrackPoint(time);
tp0->m = (tp0->m2>0.0f?sqrt(tp0->m2):0.0f);
}
if(time < last) {
TrackPoint *tp1 = getTrackPoint(time+1);
tp1->m = (tp1->m2>0.0f?sqrt(tp1->m2):0.0f);
}
}
}
bool track :: isEnded()
void Track :: step(const TimeType &time)
{
return (end!=LONG_MAX);
if(time > first && time < last) {
TrackPoint *tp = point[time-first];
tp->destroy();
point[time-first] = NULL;
}
}
void track :: push_back_tpoint(tpoint *p)
{
point.push_back(p);
}
void track :: push_back(trackpoint *p)
void Track :: push_back(TrackPoint *p)
{
point.push_back(p);
p->owner = this;
p->refCount++;
last++;
end++;
}
void track :: startTrack(trackpoint *p, bool bTail)
void Track :: endTrack(bool bStitch)
{
push_back(p);
start = p->time;
m_pDescendant = p->ph;
if(bTail) {
tailStart = 1;
start--;
trackpoint *s = new trackpoint(p);
s->time = p->time - 1;
point.insert(point.begin(),s);
m_p = p->ph;
if(bStitch) {
this->bStitch = true;
} else {
end++;
}
currtime = p->time-1;
bEnded = true;
}
trackpoint *track :: back()
void Track :: synth(float *out,
const TimeType &time,
int n,
int mode,
int c)
{
return (trackpoint*)point.back();
}
float m0, m1;
float w0, w1;
float dw;
float ph0, ph1;
bool bTailStart;
bool bTailEnd;
if(time >= end) return;
if(time < last) {
TrackPoint *tp1 = getTrackPoint(time+1);
w1 = tp1->fSynth1;
m1 = tp1->m;
ph1 = tp1->phSynth;
if(bMerge && time + 1 == last) {
m1 = 0.0f;
}
bTailStart = tp1->bJump;
bTailEnd = tp1->bJump;
} else {
bTailStart = false;
bTailEnd = (last != end);
}
if(time >= first) {
TrackPoint *tp0 = getTrackPoint(time);
w0 = tp0->fSynth0;
m0 = tp0->m;
ph0 = tp0->phSynth;
if(bSplit && time == first) {
m0 = 0.0f;
}
} else {
bTailStart = true;
}
trackpoint *track :: getTrackPoint(long time)
{
long k = time-start;
if(k<0 || k >= (long)point.size())
return NULL;
else
return (trackpoint*)point[k];
}
if(bTailEnd) {
int fall = min(n,w0==0.0f?384:min(384,(int)lrintf(PI * 4.0f / w0)));
float dm = m0 / (float)fall;
float w = w0;
float *out2 = out;
float *end = out + fall;
long iph = lrintf(ph0 * WScale);
if(iph>=W2PI) iph -= W2PI;
long iw = lrintf(w * WScale);
while(out2 != end) {
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out2 += m0 * (float)(synthTable1[i] + f * synthTable2[i]);
}
out2++;
m0 -= dm;
iph += iw;
iph &= W2PIMask;
}
}
bool track :: isStart(long synthtime)
{
return (synthtime == start);
}
if(bTailStart) {
int rise = min(n,w1==0.0f?384:min(384,(int)lrintf(PI * 3.0f / w1)));
float dm = m1 / (float)rise;
float w = w1;
out += n;
float *end = out-rise;
long iph = lrintf(ph1 * WScale);
iph &= W2PIMask;
long iw = lrintf(w * WScale);
while(out != end) {
out--;
m1 -= dm;
iph -= iw;
if(iph<0) iph += W2PI;
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out += m1 * (float)(synthTable1[i] + f * synthTable2[i]);
}
}
}
bool track :: isEnd(long synthtime)
{
return (synthtime == end);
}
if(!(bTailStart || bTailEnd)) {
float dw = (w1 - w0) / n;
float w = w0 + 0.5f * dw;
float dm = (m1 - m0) / n;
long iph = lrintf(ph0 * WScale);
if(iph>=W2PI) iph -= W2PI;
long iw = lrintf(w * WScale);
long idw = lrintf(dw * WScale) + 1;
bool track :: isDone()
{
return (currtime-start+1 >= (long)point.size()-1);
}
long track :: size()
{
return 1+end-start-tailEnd-tailStart;
}
track :: ~track() {
if(precursor) precursor->descendant = NULL;
if(descendant) descendant->precursor = NULL;
for(vector<tpoint*>::iterator i = point.begin();
i != point.end();
i++) {
delete (*i);
float *end = out + n;
while(out != end) {
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out += m0 * (float)(synthTable1[i] + f * synthTable2[i]);
}
iph += iw;
iw += idw;
iph &= W2PIMask;
m0 += dm;
out++;
}
}
}

View File

@ -1,90 +1,82 @@
// -*- mode: c++ -*-
#ifndef TRACK_H
#define TRACK_H
#include "buffer.h"
#include "trackpoint.h"
#include "config.h"
#ifdef MULTITHREADED
#include "pthread.h"
#endif
#include <stack>
#include <vector>
using namespace std;
namespace _sbsms_ {
class sms;
class renderer;
class track {
friend class renderer;
public:
void endTrack(bool bTail);
bool isEnded();
bool isDone();
void startTrack(trackpoint *p, bool bTail);
void push_back(trackpoint *p);
void push_back_tpoint(tpoint *p);
long size();
void synth(SampleBuf *out,
long writePos,
int c,
long synthtime,
int steps,
real fScale0,
real fScale1,
real mScale);
trackpoint *getTrackPoint(long time);
bool isStart(long synthtime);
bool isEnd(long synthtime);
trackpoint *back();
vector<tpoint*> point;
unsigned short index;
bool bEnd;
track *descendant;
track *precursor;
long tailEnd;
long tailStart;
long currtime;
real rise;
real fall;
long start;
long end;
real m_p;
real m_pDescendant;
int res;
sms *owner;
protected:
friend class TrackAllocator;
track(track *precursor,sms *owner,int res);
~track();
enum {
trackIndexNone = 0
};
class TrackAllocator {
public:
TrackAllocator(bool bManageIndex);
TrackAllocator(bool bManageIndex, unsigned short maxtrackindex);
void init();
int size();
~TrackAllocator();
#define PhShift 5
#define WShift 21
#define Ph1 65535
#define WPI 536870912
#define W2PI 1073741824
#define W2PIMask 1073741823
#define WScale 1.708913188941079e8f
#define MScale 4.656683928435187e-10f
track *getTrack(unsigned short index);
track *create(track *precursor,sms *owner, int res, unsigned short index);
track *create(track *precursor,sms *owner, int res);
void destroy(track *t);
enum SynthMode {
synthModeOutput = 0,
synthModeTrial2,
synthModeTrial1
};
class SMS;
class Track : public SBSMSTrack {
public:
Track(float h, TrackIndexType index, TrackPoint *p, const TimeType &time, bool bStitch);
~Track();
SBSMSTrackPoint *getSBSMSTrackPoint(const TimeType &time);
TrackIndexType getIndex();
bool isFirst(const TimeType &synthtime);
bool isLast(const TimeType &synthtime);
protected:
void push_back(TrackPoint *p);
TrackPoint *back();
void endTrack(bool bStitch);
TrackPoint *getTrackPoint(const TimeType &time);
TimeType size();
TrackPoint *updateFPH(const TimeType &time, int mode, int n, float f0, float f1);
void updateM(const TimeType &time, int mode);
void step(const TimeType &time);
void synth(float *out, const TimeType &synthtime, int n, int mode, int c);
bool jump(TrackPoint *tp0, TrackPoint *tp1);
friend class SMS;
friend class SynthRenderer;
friend class TrackPoint;
protected:
#ifdef MULTITHREADED
pthread_mutex_t taMutex;
#endif
long gIdCount;
stack<unsigned short> gTrackIndex;
vector<track*> gTrack;
bool bManageIndex;
vector<TrackPoint*> point;
float h;
float jumpThresh1;
float jumpThresh2;
TrackIndexType index;
TimeType start;
TimeType first;
TimeType end;
TimeType last;
bool bEnd;
bool bEnded;
bool bRender;
bool bStitch;
bool bSplit;
bool bMerge;
};
}

View File

@ -1,99 +1,170 @@
#include <math.h>
#include "real.h"
#include "utils.h"
#include "track.h"
#include "trackpoint.h"
#include "grain.h"
#include "track.h"
namespace _sbsms_ {
trackpoint :: trackpoint(trackpoint *tp)
void TrackPoint :: destroy()
{
init();
f = tp->f;
y = tp->y;
y0 = tp->y0;
h = tp->h;
M = tp->M;
ph = tp->ph;
owner = tp->owner;
refCount--;
if(refCount <= 0) {
delete this;
}
}
trackpoint :: ~trackpoint()
TrackPoint :: TrackPoint(Slice *slice, float *peak, audio *gx, float *mag, float *mag2, int k, int N, int band)
{
refCount = 0;
for(int d=0;d<3;d++) {
if(dup[d]) {
dup[d]->dup[2-d] = NULL;
}
}
}
trackpoint :: trackpoint(grain *g, real x, real y, int N, short M, short h, long time)
{
init();
real k = x;
int ki = round2int(k);
real kf = ki<k?k-ki:ki-k;
real norm0 = square(g->x[ki][0]) + square(g->x[ki][1]);
real ph0;
if(norm0 > 0.0f) {
ph0 = atan2(g->x[ki][1],g->x[ki][0]);
} else {
ph0 = 0.0f;
}
int ki1 = ki<k?ki+1:ki-1;
real norm1, ph1;
if(ki == N-1) {
norm1 = norm0;
ph1 = ph0;
} else {
norm1 = square(g->x[ki1][0]) + square(g->x[ki1][1]);
if(norm1 > 0.0f) {
ph1 = atan2(g->x[ki1][1],g->x[ki1][0]);
} else {
ph1 = 0.0f;
}
}
real ifreq = TWOPI*k/(real)N;
ph0 = ph0 + (real)ki*PI;
ph1 = ph1 + (real)ki1*PI;
if(kf < 0.5) {
real dp = canon(ph1 - ph0);
ph1 = ph0 + dp;
} else {
real dp = canon(ph0 - ph1);
ph0 = ph1 + dp;
}
real ph = ((1.0f-kf)*ph0 + kf*ph1);
this->time = time;
this->y = y;
this->y0 = y;
this->M = M;
this->h = h;
this->f = ifreq;
this->ph = canon(ph);
}
trackpoint :: trackpoint()
{
init();
}
void trackpoint :: init()
{
for(int d=0;d<3;d++)
dup[d] = NULL;
contF = 1e9;
cont = NULL;
dupcont = NULL;
}
dupStereo = NULL;
bJump = false;
y01 = 0.0f;
pp = NULL;
pn = NULL;
bSyncStereo = false;
bConnect = false;
bConnected = false;
bDelete = false;
bOwned = false;
bMarked = false;
bSplit = false;
bMerge = false;
owner = NULL;
this->slice = slice;
this->peak = peak;
float y0 = mag[k-1];
float y1 = mag[k];
float y2 = mag[k+1];
float d = (y0 + y2 - y1 - y1);
x = (d==0.0f?k:k + 0.5f * (y0 - y2) / d);
int ki = lrintf(x);
int ki1;
float kf;
if(ki<x) {
ki1 = ki + 1;
kf = x - ki;
} else {
ki1 = ki - 1;
kf = ki - x;
}
y = ((1.0f-kf)*mag2[ki] + kf*mag2[ki1]);
f = TWOPI*x/(float)(N*(1<<band));
float norm0 = square(gx[ki][0]) + square(gx[ki][1]);
float ph0;
if(norm0 > 0.0f) {
ph0 = atan2(gx[ki][1],gx[ki][0]);
} else {
ph0 = 0.0f;
}
float ph1;
float norm1 = square(gx[ki1][0]) + square(gx[ki1][1]);
if(norm1 > 0.0f) {
ph1 = atan2(gx[ki1][1],gx[ki1][0]);
} else {
ph1 = 0.0f;
}
ph0 += (float)(ki&1)*PI;
ph1 += (float)(ki1&1)*PI;
if(kf < 0.5f) {
ph1 = ph0 + canonPI(ph1 - ph0);
} else {
ph0 = ph1 + canonPI(ph0 - ph1);
}
ph = canon2PI((1.0f-kf)*ph0 + kf*ph1);
phSynth = ph;
}
TrackPoint :: ~TrackPoint()
{
for(int d=0;d<3;d++) {
if(dup[d]) {
m2 = 0.0f;
dup[d]->dup[2-d] = NULL;
}
}
m2 = 0;
if(slice) slice->remove(this);
if(pp && pn) {
pp->pn = pn;
pn->pp = pp;
if(!(owner && owner->bRender)) {
if(pp->y * peak[lrintf(pp->x - x)] > pn->y * peak[lrintf(pn->x - x)]) {
pp->m2 += m2;
pp->xtn2 = xtn2;
pn->xtp2 = xtn2;
} else {
pn->m2 += m2;
pp->xtn2 = xtp2;
pn->xtp2 = xtp2;
}
}
} else if(pp) {
pp->pn = NULL;
if(!(owner && owner->bRender)) {
if(y01 == 0.0f || y01 * peak[lrintf(x01 - x)] < pp->y * peak[lrintf(pp->x - x)]) {
pp->x01 = x01;
pp->y01 = y01;
pp->m2 += m2;
pp->xtn2 = xtn2;
}
}
} else if(pn) {
pn->pp = NULL;
if(!(owner && owner->bRender)) {
if(y01 == 0.0f || y01 * peak[lrintf(x01 - x)] < pn->y * peak[lrintf(pn->x - x)]) {
pn->x01 = x01;
pn->y01 = y01;
pn->m2 += m2;
pn->xtp2 = xtp2;
}
}
}
}
float TrackPoint :: getF()
{
return f;
}
float TrackPoint :: getM()
{
return y;
}
float TrackPoint :: getPhase()
{
return ph;
}
Slice :: Slice(int band, const TimeType &time)
{
this->band = band;
this->time = time;
bottom = NULL;
top = NULL;
}
void Slice :: remove(TrackPoint *tp)
{
if(tp == top) {
top = top->pp;
}
if(tp == bottom) {
bottom = bottom->pn;
}
}
Slice :: ~Slice()
{
for(TrackPoint *tp = bottom;
tp;
tp = tp->pn) {
tp->slice = NULL;
}
}
}

View File

@ -1,46 +1,77 @@
// -*- mode: c++ -*-
#ifndef TRACKPOINT_H
#define TRACKPOINT_H
#include "grain.h"
#include "sbsms.h"
namespace _sbsms_ {
class track;
enum { TrackPointNoCont = 65535 };
class tpoint {
public:
tpoint() {}
virtual ~tpoint() {}
real f;
real y;
real ph;
short h;
short M;
real y0;
class Track;
class Slice;
class TrackPoint : public SBSMSTrackPoint {
public:
TrackPoint(Slice *slice, float *peak, audio *gx, float *mag, float *mag2, int k, int N, int band);
~TrackPoint();
void destroy();
float getF();
float getM();
float getPhase();
protected:
TrackPoint *pp;
TrackPoint *pn;
TrackPoint *dupcont;
TrackPoint *dupStereo;
TrackPoint *cont;
TrackPoint *dup[3];
Track *owner;
Slice *slice;
float *peak;
float x01;
float y01;
float phSynth;
union {
float fSynth0;
float xtp2;
};
union {
float fSynth1;
float xtn2;
};
int refCount;
float f;
float x;
float y;
float ph;
float contF;
float m;
float m2;
bool bJump;
bool bSyncStereo;
bool bConnected;
bool bConnect;
bool bDelete;
bool bOwned;
bool bMarked;
bool bSplit;
bool bMerge;
friend class Slice;
friend class SMS;
friend class Track;
};
class trackpoint : public tpoint {
public:
trackpoint();
trackpoint(trackpoint *tp);
trackpoint(grain *g, real x, real y, int N, short M, short h, long time);
~trackpoint();
track *owner;
long time;
real contF;
bool bConnect;
bool bConnected;
bool bDelete;
trackpoint *dupcont;
trackpoint *cont;
trackpoint *dup[3];
protected:
void init();
class Slice {
public:
Slice(int band, const TimeType &time);
~Slice();
void remove(TrackPoint *tp);
TrackPoint *bottom;
TrackPoint *top;
int band;
TimeType time;
};
}

View File

@ -1,89 +0,0 @@
#include <math.h>
#include "utils.h"
#include "real.h"
namespace _sbsms_ {
int COSSIZE;
real *COSTABLE = NULL;
real COSFACTOR;
int *factor(int n)
{
int *f = (int*)calloc(ilog2(n)+1,sizeof(int));
factor(n,f,0);
return f;
}
void factor(int n, int *f, int m)
{
for(int k=2;k<=n;k++) {
if(n%k==0) {
f[m++] = k;
n /= k;
break;
}
}
if(n>1)
factor(n,f,m);
}
void _evenodd2c(audio *eo, audio *even, audio *odd, int N)
{
for(int k=0;k<N;k++) {
eo[k][0] = (even[k][0] - odd[k][1]);
eo[k][1] = (even[k][1] + odd[k][0]);
}
}
void _c2evenodd(audio *eo, audio *even, audio *odd, int N)
{
int Nover2 = N/2;
for(int k=0;k<=Nover2;k++) {
int fk = (k==0)?0:N-k;
real eok0 = eo[k][0];
real eok1 = eo[k][1];
real eofk0 = eo[fk][0];
real eofk1 = eo[fk][1];
even[k][0] = 0.5f*(eok0 + eofk0);
even[k][1] = 0.5f*(eok1 - eofk1);
odd[k][0] = 0.5f*(eok1 + eofk1);
odd[k][1] = 0.5f*(-eok0 + eofk0);
}
}
void cosinit(int size) {
COSSIZE = size;
COSFACTOR = (real)(COSSIZE-1)/PI;
if(COSTABLE) free(COSTABLE);
COSTABLE = (real*)malloc(size*sizeof(real));
for(int k=0;k<size;k++)
COSTABLE[k] = cos((real)k/(real)(COSSIZE-1)*PI);
}
void _c2magphase(audio *g, int N)
{
for(int k=0;k<N;k++) {
real mag = norm(g[k]);
real phase = atan2(g[k][1],g[k][0]);
g[k][0] = mag;
g[k][1] = phase;
}
}
void _magphase2c(audio *g, int N)
{
for(int k=0;k<N;k++) {
real mag = g[k][0];
real phi = g[k][1];
real re = mag * cos(phi);
real im = mag * sin(phi);
g[k][0] = re;
g[k][1] = im;
}
}
}

View File

@ -1,11 +1,10 @@
#ifndef FFTUTILS_H
#define FFTUTILS_H
// -*- mode: c++ -*-
#ifndef UTILS_H
#define UTILS_H
#include "real.h"
#include "config.h"
#include "sbsms.h"
#include <math.h>
#include <limits.h>
#include <stdlib.h>
namespace _sbsms_ {
@ -13,67 +12,56 @@ namespace _sbsms_ {
#define PI 3.1415926535897932384626433832795f
#define TWOPI 6.28318530717958647692528676655900576f
extern int COSSIZE;
extern real COSFACTOR;
extern real *COSTABLE;
void cosinit(int size);
void _evenodd2c(audio *eo, audio *even, audio *odd, int N);
void _c2evenodd(audio *eo, audio *even, audio *odd, int N);
inline real COS(real x);
inline real square(real x);
void _c2magphase(audio *g, int N);
void _magphase2c(audio *g, int N);
inline real canon(real ph);
inline real norm(audio x);
inline real norm2(audio x);
inline real sign(real x);
inline real dBApprox(real x);
int *factor(int n);
void factor(int n, int *f, int m);
inline int ilog2(int x)
inline void c2even(audio *eo, audio *even, int N)
{
int n = 0;
while(x>1) {
x>>=1;
n++;
}
return n;
int Nover2 = N/2;
even[0][0] = eo[0][0];
even[0][1] = 0.0f;
for(int k=1;k<=Nover2;k++) {
int Nk = N-k;
even[k][0] = 0.5f*(eo[k][0] + eo[Nk][0]);
even[k][1] = 0.5f*(eo[k][1] - eo[Nk][1]);
}
}
inline real dBApprox(real x)
inline void c2odd(audio *eo, audio *odd, int N)
{
real u = (x-1.0f)/(x+1.0f);
real u2 = u*u;
return 17.37177927613007f*u*(1.0f + u2*(0.333333333333333f + u2*(0.2f + u2*0.14285714285714f)));
int Nover2 = N/2;
odd[0][0] = eo[0][1];
odd[0][1] = 0.0f;
for(int k=1;k<=Nover2;k++) {
int Nk = N-k;
odd[k][0] = 0.5f*(eo[k][1] + eo[Nk][1]);
odd[k][1] = 0.5f*(eo[Nk][0] - eo[k][0]);
}
}
inline real canon(real ph)
inline float canonPI(float ph)
{
return ph - TWOPI*(real)round2int(ph*ONEOVERTWOPI);
ph -= TWOPI * lrintf(ph * ONEOVERTWOPI);
if(ph < -PI) ph += TWOPI;
else if(ph >= PI) ph -= TWOPI;
return ph;
}
inline real norm2(audio x)
inline float canon2PI(float ph)
{
return square(x[0]) + square(x[1]);
ph -= TWOPI * lrintf(ph * ONEOVERTWOPI);
if(ph < 0.0f) ph += TWOPI;
if(ph >= TWOPI) ph -= TWOPI;
return ph;
}
inline real norm(audio x)
{
return sqrt(norm2(x));
}
inline real COS(real x)
{
return COSTABLE[round2int(COSFACTOR*fabsf(x))];
}
inline real square(real x)
inline float square(float x)
{
return x*x;
}
inline float norm2(t_fft x)
{
return square(x[0]) + square(x[1]);
}
}
#endif

View File

@ -6,7 +6,7 @@ SBSMSEffect.cpp
Clayton Otey
This abstract class contains all of the common code for an
This class contains all of the common code for an
effect that uses SBSMS to do its processing (TimeScale)
**********************************************************************/
@ -22,79 +22,90 @@ effect that uses SBSMS to do its processing (TimeScale)
#include "../Project.h"
#include "TimeWarper.h"
class resampleBuf
enum {
SBSMSOutBlockSize = 512
};
class ResampleBuf
{
public:
resampleBuf()
ResampleBuf()
{
processed = 0;
buf = NULL;
leftBuffer = NULL;
rightBuffer = NULL;
quality = NULL;
iface = NULL;
sbsms = NULL;
sbsmser = NULL;
outBuf = NULL;
outputLeftBuffer = NULL;
outputRightBuffer = NULL;
resampler = NULL;
SBSMSBuf = NULL;
outputLeftTrack = NULL;
outputRightTrack = NULL;
resampler = NULL;
}
~resampleBuf()
~ResampleBuf()
{
if(buf) free(buf);
if(leftBuffer) free(leftBuffer);
if(rightBuffer) free(rightBuffer);
if(sbsmser) sbsms_destroy(sbsmser);
if(outBuf) free(outBuf);
if(outputLeftBuffer) free(outputLeftBuffer);
if(outputRightBuffer) free(outputRightBuffer);
if(SBSMSBuf) free(SBSMSBuf);
if(outputLeftTrack) delete outputLeftTrack;
if(outputRightTrack) delete outputRightTrack;
if(quality) delete quality;
if(sbsms) delete sbsms;
if(iface) delete iface;
if(resampler) delete resampler;
}
bool bPitch;
audio *buf;
double ratio;
sampleCount block;
sampleCount processed;
sampleCount blockSize;
sampleCount SBSMSBlockSize;
sampleCount offset;
sampleCount end;
float *leftBuffer;
float *rightBuffer;
WaveTrack *leftTrack;
WaveTrack *rightTrack;
SBSMS *sbsms;
SBSMSInterface *iface;
audio *SBSMSBuf;
// Not required by callbacks, but makes for easier cleanup
sbsms *sbsmser;
audio *outBuf;
float *outputLeftBuffer;
float *outputRightBuffer;
Resampler *resampler;
SBSMSQuality *quality;
WaveTrack *outputLeftTrack;
WaveTrack *outputRightTrack;
};
class SBSMSEffectInterface : public SBSMSInterfaceSliding {
public:
SBSMSEffectInterface(Resampler *resampler,
Slide *rateSlide, Slide *pitchSlide,
bool bReferenceInput,
long samples, long preSamples,
SBSMSQuality *quality)
: SBSMSInterfaceSliding(rateSlide,pitchSlide,bReferenceInput,samples,preSamples,quality)
{
this->resampler = resampler;
}
virtual ~SBSMSEffectInterface() {}
long samples(audio *buf, long n) {
return resampler->read(buf, n);
}
protected:
Resampler *resampler;
};
long samplesCB(audio *chdata, long numFrames, void *userData)
{
sbsmsInfo *si = (sbsmsInfo*) userData;
long n_read = si->rs->read(chdata, numFrames);
return n_read;
}
void EffectSBSMS :: setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, bool bPreAnalyze)
long resampleCB(void *cb_data, SBSMSFrame *data)
{
this->rateStart = rateStart;
this->rateEnd = rateEnd;
this->pitchStart = pitchStart;
this->pitchEnd = pitchEnd;
this->bPreAnalyze = bPreAnalyze;
}
bool EffectSBSMS :: bInit = FALSE;
long resampleCB(void *cb_data, sbsms_resample_frame *data)
{
resampleBuf *r = (resampleBuf*) cb_data;
ResampleBuf *r = (ResampleBuf*) cb_data;
long blockSize = r->leftTrack->GetBestBlockSize(r->offset);
@ -112,29 +123,75 @@ long resampleCB(void *cb_data, sbsms_resample_frame *data)
r->buf[i][1] = r->rightBuffer[i];
}
r->offset += blockSize;
data->in = r->buf;
data->buf = r->buf;
data->size = blockSize;
data->ratio0 = r->ratio;
data->ratio1 = r->ratio;
if(r->bPitch) {
float t0 = (float)(r->processed) / r->iface->getSamplesToInput();
float t1 = (float)(r->processed + blockSize) / r->iface->getSamplesToInput();
data->ratio0 = r->iface->getStretch(t0);
data->ratio1 = r->iface->getStretch(t1);
} else {
data->ratio0 = r->ratio;
data->ratio1 = r->ratio;
}
r->processed += blockSize;
r->offset += blockSize;
return blockSize;
}
long postResampleCB(void *cb_data, SBSMSFrame *data)
{
ResampleBuf *r = (ResampleBuf*) cb_data;
long sampleCount = r->sbsms->read(r->iface, r->SBSMSBuf, r->SBSMSBlockSize);
data->buf = r->SBSMSBuf;
data->size = sampleCount;
data->ratio0 = 1.0 / r->ratio;
data->ratio1 = 1.0 / r->ratio;
return sampleCount;
}
void EffectSBSMS :: setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd,
SlideType rateSlideType, SlideType pitchSlideType,
bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput)
{
this->rateStart = rateStart;
this->rateEnd = rateEnd;
this->pitchStart = pitchStart;
this->pitchEnd = pitchEnd;
this->bLinkRatePitch = bLinkRatePitch;
this->rateSlideType = rateSlideType;
this->pitchSlideType = pitchSlideType;
this->bRateReferenceInput = bRateReferenceInput;
this->bPitchReferenceInput = bPitchReferenceInput;
}
TimeWarper *createTimeWarper(double t0, double t1, double duration,
double rateStart, double rateEnd, SlideType rateSlideType)
{
TimeWarper *warper = NULL;
if (rateStart == rateEnd || rateSlideType == SlideConstant) {
warper = new LinearTimeWarper(t0, t0, t1, t0+duration);
} else if(rateSlideType == SlideLinearInputRate) {
warper = new LinearInputRateTimeWarper(t0, t1, rateStart, rateEnd);
} else if(rateSlideType == SlideLinearOutputRate) {
warper = new LinearOutputRateTimeWarper(t0, t1, rateStart, rateEnd);
} else if(rateSlideType == SlideLinearInputStretch) {
warper = new LinearInputStretchTimeWarper(t0, t1, rateStart, rateEnd);
} else if(rateSlideType == SlideLinearOutputStretch) {
warper = new LinearOutputStretchTimeWarper(t0, t1, rateStart, rateEnd);
} else if(rateSlideType == SlideGeometricInput) {
warper = new GeometricInputTimeWarper(t0, t1, rateStart, rateEnd);
} else if(rateSlideType == SlideGeometricOutput) {
warper = new GeometricOutputTimeWarper(t0, t1, rateStart, rateEnd);
}
return warper;
}
// Labels inside the affected region are moved to match the audio; labels after
// it are shifted along appropriately.
bool EffectSBSMS::ProcessLabelTrack(Track *t)
{
TimeWarper *warper = NULL;
if (rateStart == rateEnd)
{
warper = new LinearTimeWarper(mT0, mT0,
mT1, mT0+(mT1-mT0)*mTotalStretch);
} else
{
warper = new LogarithmicTimeWarper(mT0, mT1,
rateStart, rateEnd);
}
TimeWarper *warper = createTimeWarper(mT0,mT1,(mT1-mT0)*mTotalStretch,rateStart,rateEnd,rateSlideType);
SetTimeWarper(new RegionTimeWarper(mT0, mT1, warper));
LabelTrack *lt = (LabelTrack*)t;
if (lt == NULL) return false;
@ -144,16 +201,10 @@ bool EffectSBSMS::ProcessLabelTrack(Track *t)
bool EffectSBSMS::Process()
{
if(!bInit) {
sbsms_init(8192);
bInit = TRUE;
}
bool bGoodResult = true;
//Iterate over each track
// Track::All is needed because this effect needs to introduce
// silence in the group tracks to keep sync-lock.
//Track::All is needed because this effect needs to introduce silence in the group tracks to keep sync
this->CopyInputTracks(Track::All); // Set up mOutputTracks.
TrackListIterator iter(mOutputTracks);
Track* t;
@ -161,13 +212,11 @@ bool EffectSBSMS::Process()
double maxDuration = 0.0;
if(rateStart == rateEnd)
mTotalStretch = 1.0/rateStart;
else
mTotalStretch = 1.0/(rateEnd-rateStart)*log(rateEnd/rateStart);
// Must sync if selection length will change
bool mustSync = (mTotalStretch != 1.0);
bool mustSync = (rateStart != rateEnd);
Slide rateSlide(rateSlideType,rateStart,rateEnd);
Slide pitchSlide(pitchSlideType,pitchStart,pitchEnd);
mTotalStretch = rateSlide.getTotalStretch();
t = iter.First();
while (t != NULL) {
@ -218,131 +267,116 @@ bool EffectSBSMS::Process()
mCurTrackNum++; // Increment for rightTrack, too.
}
sampleCount trackStart = leftTrack->TimeToLongSamples(leftTrack->GetStartTime());
sampleCount trackEnd = leftTrack->TimeToLongSamples(leftTrack->GetEndTime());
// SBSMS has a fixed sample rate - we just convert to its sample rate and then convert back
float srIn = leftTrack->GetRate();
// mchinen: srSBMS doesn't do the right thing when it was set to fixed 44100. This seems to fix it.
float srSBSMS = leftTrack->GetRate();
float srTrack = leftTrack->GetRate();
float srProcess = bLinkRatePitch?srTrack:44100.0;
// the resampler needs a callback to supply its samples
resampleBuf rb;
ResampleBuf rb;
sampleCount maxBlockSize = leftTrack->GetMaxBlockSize();
rb.block = maxBlockSize;
rb.buf = (audio*)calloc(rb.block,sizeof(audio));
rb.blockSize = maxBlockSize;
rb.buf = (audio*)calloc(rb.blockSize,sizeof(audio));
rb.leftTrack = leftTrack;
rb.rightTrack = rightTrack?rightTrack:leftTrack;
rb.leftBuffer = (float*)calloc(maxBlockSize,sizeof(float));
rb.rightBuffer = (float*)calloc(maxBlockSize,sizeof(float));
rb.offset = start;
rb.end = trackEnd;
rb.ratio = srSBSMS/srIn;
rb.resampler = new Resampler(resampleCB, &rb);
// Samples in selection
sampleCount samplesIn = end-start;
// Samples for SBSMS to process after resampling
sampleCount samplesToProcess = (sampleCount) ((real)samplesIn*(srSBSMS/srIn));
sampleCount samplesToProcess = (sampleCount) ((float)samplesIn*(srProcess/srTrack));
SlideType outSlideType;
SBSMSResampleCB outResampleCB;
sampleCount processPresamples = 0;
sampleCount trackPresamples = 0;
if(bLinkRatePitch) {
rb.bPitch = true;
outSlideType = rateSlideType;
outResampleCB = resampleCB;
rb.offset = start;
rb.end = end;
rb.iface = new SBSMSInterfaceSliding(&rateSlide,&pitchSlide,
bPitchReferenceInput,
samplesToProcess,0,
NULL);
} else {
rb.bPitch = false;
outSlideType = (srProcess==srTrack?SlideIdentity:SlideConstant);
outResampleCB = postResampleCB;
rb.ratio = srProcess/srTrack;
rb.quality = new SBSMSQuality(&SBSMSQualityStandard);
rb.resampler = new Resampler(resampleCB, &rb, srProcess==srTrack?SlideIdentity:SlideConstant);
rb.sbsms = new SBSMS(rightTrack?2:1,rb.quality,true);
rb.SBSMSBlockSize = rb.sbsms->getInputFrameSize();
rb.SBSMSBuf = (audio*)calloc(rb.SBSMSBlockSize,sizeof(audio));
processPresamples = wxMin(rb.quality->getMaxPresamples(),
(long)((float)(start-trackStart)*(srProcess/srTrack)));
trackPresamples = wxMin(start-trackStart,
(long)((float)(processPresamples)*(srTrack/srProcess)));
rb.offset = start - trackPresamples;
rb.end = trackEnd;
rb.iface = new SBSMSEffectInterface(rb.resampler,
&rateSlide,&pitchSlide,
bPitchReferenceInput,
samplesToProcess,processPresamples,
rb.quality);
}
Resampler resampler(outResampleCB,&rb,outSlideType);
audio outBuf[SBSMSOutBlockSize];
float outBufLeft[2*SBSMSOutBlockSize];
float outBufRight[2*SBSMSOutBlockSize];
// Samples in output after SBSMS
sampleCount samplesToOutput = rb.iface->getSamplesToOutput();
// Samples in output after resampling back
sampleCount samplesToGenerate = (sampleCount) ((real)samplesToProcess * mTotalStretch);
sampleCount samplesOut = (sampleCount) ((real)samplesIn * mTotalStretch);
sampleCount samplesOut = (sampleCount) ((float)samplesToOutput * (srTrack/srProcess));
// Duration in track time
double duration = (mCurT1-mCurT0) * mTotalStretch;
if(duration > maxDuration)
maxDuration = duration;
TimeWarper *warper = NULL;
if (rateStart == rateEnd)
{
warper = new LinearTimeWarper(mCurT0, mCurT0,
mCurT1, mCurT0+maxDuration);
} else
{
warper = new LogarithmicTimeWarper(mCurT0, mCurT1,
rateStart, rateEnd);
}
TimeWarper *warper = createTimeWarper(mCurT0,mCurT1,maxDuration,rateStart,rateEnd,rateSlideType);
SetTimeWarper(warper);
sbsmsInfo si;
si.rs = rb.resampler;
si.samplesToProcess = samplesToProcess;
si.samplesToGenerate = samplesToGenerate;
si.rate0 = rateStart;
si.rate1 = rateEnd;
si.pitch0 = pitchStart;
si.pitch1 = pitchEnd;
sbsms_quality quality = sbsms_quality_fast;
rb.sbsmser = sbsms_create(&samplesCB,&rateCBLinear,&pitchCBLinear,rightTrack?2:1,&quality,bPreAnalyze,true);
rb.outputLeftTrack = mFactory->NewWaveTrack(leftTrack->GetSampleFormat(),
leftTrack->GetRate());
if(rightTrack)
rb.outputRightTrack = mFactory->NewWaveTrack(rightTrack->GetSampleFormat(),
rightTrack->GetRate());
sampleCount blockSize = quality.maxoutframesize;
rb.outBuf = (audio*)calloc(blockSize,sizeof(audio));
rb.outputLeftBuffer = (float*)calloc(blockSize*2,sizeof(float));
if(rightTrack)
rb.outputRightBuffer = (float*)calloc(blockSize*2,sizeof(float));
long pos = 0;
long outputCount = -1;
// pre analysis
real fracPre = 0.0f;
if(bPreAnalyze) {
fracPre = 0.05f;
resampleBuf rbPre;
rbPre.block = maxBlockSize;
rbPre.buf = (audio*)calloc(rb.block,sizeof(audio));
rbPre.leftTrack = leftTrack;
rbPre.rightTrack = rightTrack?rightTrack:leftTrack;
rbPre.leftBuffer = (float*)calloc(maxBlockSize,sizeof(float));
rbPre.rightBuffer = (float*)calloc(maxBlockSize,sizeof(float));
rbPre.offset = start;
rbPre.end = end;
rbPre.ratio = srSBSMS/srIn;
rbPre.resampler = new Resampler(resampleCB, &rbPre);
si.rs = rbPre.resampler;
long pos = 0;
long lastPos = 0;
long ret = 0;
while(lastPos<samplesToProcess) {
ret = sbsms_pre_analyze(&samplesCB,&si,rb.sbsmser);
lastPos = pos;
pos += ret;
real completion = (real)lastPos/(real)samplesToProcess;
if (TrackProgress(0,fracPre*completion))
return false;
}
sbsms_pre_analyze_complete(rb.sbsmser);
sbsms_reset(rb.sbsmser);
si.rs = rb.resampler;
}
// process
while(pos<samplesOut && outputCount) {
outputCount = sbsms_read_frame(rb.outBuf, &si, rb.sbsmser, NULL, NULL);
if(pos+outputCount>samplesOut) {
outputCount = samplesOut - pos;
long frames;
if(pos+SBSMSOutBlockSize>samplesOut) {
frames = samplesOut - pos;
} else {
frames = SBSMSOutBlockSize;
}
outputCount = resampler.read(outBuf,frames);
for(int i = 0; i < outputCount; i++) {
rb.outputLeftBuffer[i] = rb.outBuf[i][0];
outBufLeft[i] = outBuf[i][0];
if(rightTrack)
rb.outputRightBuffer[i] = rb.outBuf[i][1];
outBufRight[i] = outBuf[i][1];
}
pos += outputCount;
rb.outputLeftTrack->Append((samplePtr)rb.outputLeftBuffer, floatSample, outputCount);
rb.outputLeftTrack->Append((samplePtr)outBufLeft, floatSample, outputCount);
if(rightTrack)
rb.outputRightTrack->Append((samplePtr)rb.outputRightBuffer, floatSample, outputCount);
rb.outputRightTrack->Append((samplePtr)outBufRight, floatSample, outputCount);
double frac = (double)pos/(double)samplesOut;
int nWhichTrack = mCurTrackNum;
@ -356,7 +390,7 @@ bool EffectSBSMS::Process()
frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once.
}
}
if (TrackProgress(nWhichTrack, fracPre + (1.0-fracPre)*frac))
if (TrackProgress(nWhichTrack, frac))
return false;
}
rb.outputLeftTrack->Flush();

View File

@ -21,22 +21,23 @@
#include "sbsms.h"
using namespace _sbsms_;
class WaveTrack;
class EffectSBSMS : public Effect {
public:
static bool bInit;
virtual bool Process();
void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd, bool bPreAnalyze);
void setParameters(double rateStart, double rateEnd, double pitchStart, double pitchEnd,
SlideType rateSlideType, SlideType pitchSlideType,
bool bLinkRatePitch, bool bRateReferenceInput, bool bPitchReferenceInput);
private:
bool ProcessLabelTrack(Track *track);
double rateStart, rateEnd, pitchStart, pitchEnd;
bool bPreAnalyze;
bool bLinkRatePitch, bRateReferenceInput, bPitchReferenceInput;
SlideType rateSlideType;
SlideType pitchSlideType;
int mCurTrackNum;
double mCurT0;
double mCurT1;
real mTotalStretch;
float mTotalStretch;
};
#endif

View File

@ -27,6 +27,8 @@
#include "../ShuttleGui.h"
#include <math.h>
#include <iostream>
using namespace std;
#include <wx/sizer.h>
#include <wx/stattext.h>
@ -38,7 +40,7 @@
// EffectTimeScale
//
EffectTimeScale::EffectTimeScale()
EffectTimeScale::EffectTimeScale()
{
m_RatePercentChangeStart = 0;
m_RatePercentChangeEnd = 0;
@ -46,7 +48,13 @@ EffectTimeScale::EffectTimeScale()
m_PitchHalfStepsEnd = 0;
m_PitchPercentChangeStart = 0;
m_PitchPercentChangeEnd = 0;
m_PreAnalyze = false;
m_RateSlideType = 0;
m_PitchSlideType = 0;
m_RateSlideReference = 0;
m_PitchSlideReference = 0;
m_RateLinkInitialFinal = false;
m_PitchLinkInitialFinal = false;
m_LinkRatePitch = false;
}
wxString EffectTimeScale::GetEffectDescription() {
@ -68,7 +76,13 @@ bool EffectTimeScale::PromptUser()
dlog.m_PitchHalfStepsEnd = m_PitchHalfStepsEnd;
dlog.m_PitchPercentChangeStart = m_PitchPercentChangeStart;
dlog.m_PitchPercentChangeEnd = m_PitchPercentChangeEnd;
dlog.m_PreAnalyze = m_PreAnalyze;
dlog.m_LinkRatePitch = m_LinkRatePitch;
dlog.m_RateSlideType = m_RateSlideType;
dlog.m_PitchSlideType = m_PitchSlideType;
dlog.m_RateSlideReference = m_RateSlideReference;
dlog.m_PitchSlideReference = m_PitchSlideReference;
dlog.m_RateLinkInitialFinal = m_RateLinkInitialFinal;
dlog.m_PitchLinkInitialFinal = m_PitchLinkInitialFinal;
// Don't need to call TransferDataToWindow, although other
// Audacity dialogs (from which I derived this one) do it, because
@ -86,7 +100,13 @@ bool EffectTimeScale::PromptUser()
m_PitchHalfStepsEnd = dlog.m_PitchHalfStepsEnd;
m_PitchPercentChangeStart = dlog.m_PitchPercentChangeStart;
m_PitchPercentChangeEnd = dlog.m_PitchPercentChangeEnd;
m_PreAnalyze = dlog.m_PreAnalyze;
m_LinkRatePitch = dlog.m_LinkRatePitch;
m_RateSlideType = dlog.m_RateSlideType;
m_PitchSlideType = dlog.m_PitchSlideType;
m_RateSlideReference = dlog.m_RateSlideReference;
m_PitchSlideReference = dlog.m_PitchSlideReference;
m_RateLinkInitialFinal = dlog.m_RateLinkInitialFinal;
m_PitchLinkInitialFinal = dlog.m_PitchLinkInitialFinal;
return true;
}
@ -99,14 +119,15 @@ bool EffectTimeScale::TransferParameters( Shuttle & shuttle )
shuttle.TransferDouble(wxT("PitchHalfStepsEnd"),m_PitchHalfStepsEnd,0.0);
shuttle.TransferDouble(wxT("PitchPercentChangeStart"),m_PitchPercentChangeStart,0.0);
shuttle.TransferDouble(wxT("PitchPercentChangeEnd"),m_PitchPercentChangeEnd,0.0);
shuttle.TransferBool(wxT("PreAnalyze"),m_PreAnalyze,false);
return true;
}
shuttle.TransferBool(wxT("LinkRatePitch"),m_LinkRatePitch,false);
shuttle.TransferInt(wxT("RateSlideType"),m_RateSlideType,0);
shuttle.TransferInt(wxT("PitchSlideType"),m_PitchSlideType,0);
shuttle.TransferInt(wxT("RateSlideReference"),m_RateSlideReference,0);
shuttle.TransferInt(wxT("PitchSlideReference"),m_PitchSlideReference,0);
shuttle.TransferBool(wxT("RateLinkInitialFinal"),m_RateLinkInitialFinal,false);
shuttle.TransferBool(wxT("PitchLinkInitialFinal"),m_PitchLinkInitialFinal,false);
inline double InvertedPercentChangeToRatio(double percentChange)
{
//mchinen hack: invert the ratio so it works with the sbsms bug which requires the reciprocal number.
return 1.0/(1.0 + percentChange / 100.0);
return true;
}
inline double PercentChangeToRatio(double percentChange)
@ -121,19 +142,50 @@ inline double HalfStepsToPercentChange(double halfSteps)
inline double PercentChangeToHalfSteps(double percentChange)
{
// mchinen: hack: take the negative of this so the correct value is displayed
// (see the InvertedPercentChangeToRatio hack for why this is needed)
return 17.312340490667560888319096172023 * log(PercentChangeToRatio(percentChange));
}
bool EffectTimeScale::Process()
{
// The pitch part of sbsms is backwards, so use an inverted function
double pitchStart = InvertedPercentChangeToRatio(m_PitchPercentChangeStart);
double pitchEnd = InvertedPercentChangeToRatio(m_PitchPercentChangeEnd);
double pitchStart = PercentChangeToRatio(m_PitchPercentChangeStart);
double pitchEnd = PercentChangeToRatio(m_PitchPercentChangeEnd);
double rateStart = PercentChangeToRatio(m_RatePercentChangeStart);
double rateEnd = PercentChangeToRatio(m_RatePercentChangeEnd);
this->EffectSBSMS::setParameters(rateStart,rateEnd,pitchStart,pitchEnd,m_PreAnalyze);
SlideType rateSlideType;
SlideType pitchSlideType;
if(rateStart == rateEnd || m_RateLinkInitialFinal) {
rateSlideType = SlideConstant;
} else if(m_RateSlideType == 0) {
if(m_RateSlideReference == 1) {
rateSlideType = SlideLinearInputRate;
} else {
rateSlideType = SlideLinearOutputRate;
}
} else if(m_RateSlideType == 1) {
if(m_RateSlideReference == 1) {
rateSlideType = SlideLinearInputStretch;
} else {
rateSlideType = SlideLinearOutputStretch;
}
} else if(m_RateSlideType == 2) {
if(m_RateSlideReference == 1) {
rateSlideType = SlideGeometricInput;
} else {
rateSlideType = SlideGeometricOutput;
}
}
if(pitchStart == pitchEnd || m_PitchLinkInitialFinal) {
pitchSlideType = SlideConstant;
} else if(m_PitchSlideType == 0) {
pitchSlideType = SlideLinearInputRate;
} else if(m_PitchSlideType == 1) {
pitchSlideType = SlideLinearInputStretch;
} else if(m_PitchSlideType == 2) {
pitchSlideType = SlideGeometricInput;
}
bool rateReferenceInput = (m_RateSlideReference == 1);
bool pitchReferenceInput = (m_PitchSlideReference == 1);
this->EffectSBSMS::setParameters(rateStart,rateEnd,pitchStart,pitchEnd,rateSlideType,pitchSlideType,m_LinkRatePitch,rateReferenceInput,pitchReferenceInput);
return this->EffectSBSMS::Process();
}
@ -141,16 +193,15 @@ bool EffectTimeScale::Process()
// TimeScaleDialog
//----------------------------------------------------------------------------
#define RATE_PERCENTCHANGE_MAX_SLIDER 150
#define RATE_PERCENTCHANGE_MIN_SLIDER -75
#define RATE_PERCENTCHANGE_MAX_TEXT 500
#define RATE_PERCENTCHANGE_MAX_SLIDER 150
#define RATE_PERCENTCHANGE_MIN_TEXT -90
#define RATE_PERCENTCHANGE_MAX_TEXT 500
#define RATE_PERCENTCHANGE_DEFAULT 0
#define PITCH_HALFSTEPS_MIN_TEXT -12
#define PITCH_HALFSTEPS_MAX_TEXT 12
#define PITCH_PERCENTCHANGE_MIN_TEXT -50
#define PITCH_PERCENTCHANGE_MAX_TEXT 100
#define PITCH_HALFSTEPS_MIN_TEXT -24
#define PITCH_HALFSTEPS_MAX_TEXT 24
#define PITCH_PERCENTCHANGE_MIN_TEXT -75
#define PITCH_PERCENTCHANGE_MAX_TEXT 300
#define ID_TEXT_RATE_PERCENTCHANGE_START 10001
#define ID_TEXT_RATE_PERCENTCHANGE_END 10002
@ -160,7 +211,13 @@ bool EffectTimeScale::Process()
#define ID_TEXT_PITCH_PERCENTCHANGE_END 10006
#define ID_SLIDER_RATE_PERCENTCHANGE_START 10007
#define ID_SLIDER_RATE_PERCENTCHANGE_END 10008
#define ID_CHECKBOX_PREANALYZE 10009
#define ID_CHECKBOX_LINKRATEPITCH 10010
#define ID_CHOICE_RATE_SLIDETYPE 10011
#define ID_CHOICE_PITCH_SLIDETYPE 10012
#define ID_CHOICE_RATE_SLIDEREFERENCE 10013
#define ID_CHOICE_PITCH_SLIDEREFERENCE 10014
#define ID_CHECKBOX_RATE_LINKINITIALFINAL 10015
#define ID_CHECKBOX_PITCH_LINKINITIALFINAL 10016
// event table for TimeScaleDialog
@ -173,13 +230,31 @@ BEGIN_EVENT_TABLE(TimeScaleDialog, EffectDialog)
EVT_TEXT(ID_TEXT_PITCH_PERCENTCHANGE_END, TimeScaleDialog::OnText_PitchPercentChangeEnd)
EVT_SLIDER(ID_SLIDER_RATE_PERCENTCHANGE_START, TimeScaleDialog::OnSlider_RatePercentChangeStart)
EVT_SLIDER(ID_SLIDER_RATE_PERCENTCHANGE_END, TimeScaleDialog::OnSlider_RatePercentChangeEnd)
EVT_CHECKBOX(ID_CHECKBOX_PREANALYZE, TimeScaleDialog::OnCheckBox_PreAnalyze)
EVT_CHECKBOX(ID_CHECKBOX_LINKRATEPITCH, TimeScaleDialog::OnCheckBox_LinkRatePitch)
EVT_CHOICE(ID_CHOICE_RATE_SLIDETYPE, TimeScaleDialog::OnChoice_RateSlideType)
EVT_CHOICE(ID_CHOICE_PITCH_SLIDETYPE, TimeScaleDialog::OnChoice_PitchSlideType)
EVT_CHOICE(ID_CHOICE_RATE_SLIDEREFERENCE, TimeScaleDialog::OnChoice_RateSlideReference)
EVT_CHOICE(ID_CHOICE_PITCH_SLIDEREFERENCE, TimeScaleDialog::OnChoice_PitchSlideReference)
EVT_CHECKBOX(ID_CHECKBOX_RATE_LINKINITIALFINAL, TimeScaleDialog::OnCheckBox_RateLinkInitialFinal)
EVT_CHECKBOX(ID_CHECKBOX_PITCH_LINKINITIALFINAL, TimeScaleDialog::OnCheckBox_PitchLinkInitialFinal)
EVT_BUTTON(ID_EFFECT_PREVIEW, TimeScaleDialog::OnPreview)
END_EVENT_TABLE()
TimeScaleDialog::TimeScaleDialog(EffectTimeScale *effect, wxWindow *parent)
: EffectDialog(parent, _("Time Scale"), INSERT_EFFECT),
: EffectDialog(parent, _("Time Scale"), PROCESS_EFFECT),
mEffect(effect)
{
rateSlideTypes.Add(_("Linear Rate"));
rateSlideTypes.Add(_("Linear Stretch"));
rateSlideTypes.Add(_("Geometric"));
pitchSlideTypes.Add(_("Linear Rate"));
pitchSlideTypes.Add(_("Linear Stretch"));
pitchSlideTypes.Add(_("Geometric"));
rateSlideReferences.Add(_("Output"));
rateSlideReferences.Add(_("Input"));
pitchSlideReferences.Add(_("Output"));
pitchSlideReferences.Add(_("Input"));
m_bLoopDetect = false;
// NULL out these control members because there are some cases where the
@ -194,7 +269,13 @@ TimeScaleDialog::TimeScaleDialog(EffectTimeScale *effect, wxWindow *parent)
m_pTextCtrl_PitchPercentChangeEnd = NULL;
m_pTextCtrl_PitchHalfStepsStart = NULL;
m_pTextCtrl_PitchHalfStepsEnd = NULL;
m_pCheckBox_PreAnalyze = NULL;
m_pCheckBox_LinkRatePitch = NULL;
m_pChoice_RateSlideType = NULL;
m_pChoice_PitchSlideType = NULL;
m_pChoice_RateSlideReference = NULL;
m_pChoice_PitchSlideReference = NULL;
m_pCheckBox_RateLinkInitialFinal = NULL;
m_pCheckBox_PitchLinkInitialFinal = NULL;
// effect parameters
m_RatePercentChangeStart = 0;
@ -203,17 +284,27 @@ TimeScaleDialog::TimeScaleDialog(EffectTimeScale *effect, wxWindow *parent)
m_PitchPercentChangeEnd = 0;
m_PitchHalfStepsStart = 0;
m_PitchHalfStepsEnd = 0;
m_PreAnalyze = false;
m_LinkRatePitch = false;
m_RateSlideType = 0;
m_PitchSlideType = 0;
m_RateSlideReference = 0;
m_PitchSlideReference = 0;
m_RateLinkInitialFinal = false;
m_PitchLinkInitialFinal = false;
Init();
}
void TimeScaleDialog::OnPreview(wxCommandEvent & event)
{
mEffect->Preview();
}
void TimeScaleDialog::PopulateOrExchange(ShuttleGui & S)
{
wxTextValidator nullvld(wxFILTER_INCLUDE_CHAR_LIST);
wxTextValidator numvld(wxFILTER_NUMERIC);
S.SetBorder(10);
S.StartHorizontalLay(wxCENTER, false);
{
@ -223,94 +314,130 @@ void TimeScaleDialog::PopulateOrExchange(ShuttleGui & S)
}
S.EndHorizontalLay();
S.SetBorder(5);
S.StartMultiColumn(2, 0);
// Rate Start
S.StartStatic(_("Initial Tempo Change (%)"));
S.StartStatic(_("Tempo Change"));
{
S.StartMultiColumn(1, wxCENTER);
S.StartHorizontalLay(wxEXPAND);
{
m_pTextCtrl_RatePercentChangeStart = S.Id(ID_TEXT_RATE_PERCENTCHANGE_START)
.AddTextBox(wxT(""), wxT(""), 12);
m_pTextCtrl_RatePercentChangeStart->SetValidator(numvld);
S.StartVerticalLay(wxCENTER);
{
S.StartHorizontalLay(wxCENTER,0);
{
m_pTextCtrl_RatePercentChangeStart = S.Id(ID_TEXT_RATE_PERCENTCHANGE_START)
.AddTextBox(_("Initial (%)"), wxT(""), 12);
m_pTextCtrl_RatePercentChangeStart->SetValidator(numvld);
}
S.EndHorizontalLay();
S.StartHorizontalLay(wxEXPAND,0);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_RatePercentChangeStart = S.Id(ID_SLIDER_RATE_PERCENTCHANGE_START)
.AddSlider(wxT(""), (int)RATE_PERCENTCHANGE_DEFAULT, (int)RATE_PERCENTCHANGE_MAX_SLIDER, (int)RATE_PERCENTCHANGE_MIN_SLIDER);
}
S.EndHorizontalLay();
}
S.EndVerticalLay();
S.StartVerticalLay(wxCENTER);
{
S.StartHorizontalLay(wxCENTER,0);
{
m_pTextCtrl_RatePercentChangeEnd = S.Id(ID_TEXT_RATE_PERCENTCHANGE_END)
.AddTextBox(_("Final (%)"), wxT(""), 12);
m_pTextCtrl_RatePercentChangeEnd->SetValidator(numvld);
}
S.EndHorizontalLay();
S.StartHorizontalLay(wxEXPAND,0);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_RatePercentChangeEnd = S.Id(ID_SLIDER_RATE_PERCENTCHANGE_END)
.AddSlider(wxT(""), (int)RATE_PERCENTCHANGE_DEFAULT, (int)RATE_PERCENTCHANGE_MAX_SLIDER, (int)RATE_PERCENTCHANGE_MIN_SLIDER);
}
S.EndHorizontalLay();
}
S.EndVerticalLay();
}
S.EndMultiColumn();
S.StartHorizontalLay(wxEXPAND,0);
S.EndHorizontalLay();
S.StartHorizontalLay(0,0);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_RatePercentChangeStart = S.Id(ID_SLIDER_RATE_PERCENTCHANGE_START)
.AddSlider(wxT(""), (int)RATE_PERCENTCHANGE_DEFAULT, (int)RATE_PERCENTCHANGE_MAX_SLIDER, (int)RATE_PERCENTCHANGE_MIN_SLIDER);
m_pChoice_RateSlideType = S.Id(ID_CHOICE_RATE_SLIDETYPE)
.AddChoice(_("Slide Type"),_("Linear Rate"),&rateSlideTypes);
m_pChoice_RateSlideType->SetSelection(0);
m_pChoice_RateSlideType->SetSizeHints(-1,-1);
m_pChoice_RateSlideReference = S.Id(ID_CHOICE_RATE_SLIDEREFERENCE)
.AddChoice(_("Reference"),_("Output"),&rateSlideReferences);
m_pChoice_RateSlideReference->SetSelection(0);
m_pChoice_RateSlideReference->SetSizeHints(-1,-1);
m_pCheckBox_RateLinkInitialFinal = S.Id(ID_CHECKBOX_RATE_LINKINITIALFINAL)
.AddCheckBox(_("Link Initial/Final"), wxT("false"));
}
S.EndHorizontalLay();
}
S.EndStatic();
S.StartStatic(_("Final Tempo Change (%)"));
// Pitch Change
S.StartStatic(_("Pitch Shift"));
{
S.StartMultiColumn(1, wxCENTER);
S.StartMultiColumn(2, wxCENTER);
{
m_pTextCtrl_RatePercentChangeEnd = S.Id(ID_TEXT_RATE_PERCENTCHANGE_END)
.AddTextBox(wxT(""), wxT(""), 12);
m_pTextCtrl_RatePercentChangeEnd->SetValidator(numvld);
S.StartMultiColumn(2, wxCENTER);
{
m_pTextCtrl_PitchHalfStepsStart = S.Id(ID_TEXT_PITCH_HALFSTEPS_START)
.AddTextBox(_("Initial (semitones) [-24 to 24]:"), wxT(""), 12);
m_pTextCtrl_PitchHalfStepsStart->SetValidator(numvld);
m_pTextCtrl_PitchPercentChangeStart = S.Id(ID_TEXT_PITCH_PERCENTCHANGE_START)
.AddTextBox(_("Initial (%) [-75 to 300]:"), wxT(""), 12);
m_pTextCtrl_PitchPercentChangeStart->SetValidator(numvld);
}
S.EndMultiColumn();
S.StartMultiColumn(2, wxCENTER);
{
m_pTextCtrl_PitchHalfStepsEnd = S.Id(ID_TEXT_PITCH_HALFSTEPS_END)
.AddTextBox(_("Final (semitones) [-24 to 24]:"), wxT(""), 12);
m_pTextCtrl_PitchHalfStepsEnd->SetValidator(numvld);
m_pTextCtrl_PitchPercentChangeEnd = S.Id(ID_TEXT_PITCH_PERCENTCHANGE_END)
.AddTextBox(_("Final (%) [-75 to 300]:"), wxT(""), 12);
m_pTextCtrl_PitchPercentChangeEnd->SetValidator(numvld);
}
S.EndMultiColumn();
}
S.EndMultiColumn();
S.StartHorizontalLay(wxEXPAND,0);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pSlider_RatePercentChangeEnd = S.Id(ID_SLIDER_RATE_PERCENTCHANGE_END)
.AddSlider(wxT(""), (int)RATE_PERCENTCHANGE_DEFAULT, (int)RATE_PERCENTCHANGE_MAX_SLIDER, (int)RATE_PERCENTCHANGE_MIN_SLIDER);
S.StartHorizontalLay(0,0);
{
m_pChoice_PitchSlideType = S.Id(ID_CHOICE_PITCH_SLIDETYPE)
.AddChoice(_("Slide Type"),_("Linear"),&pitchSlideTypes);
m_pChoice_PitchSlideType->SetSelection(0);
m_pChoice_PitchSlideType->SetSizeHints(-1,-1);
m_pChoice_PitchSlideReference = S.Id(ID_CHOICE_PITCH_SLIDEREFERENCE)
.AddChoice(_("Reference"),_("Output"),&pitchSlideReferences);
m_pChoice_PitchSlideReference->SetSelection(0);
m_pChoice_PitchSlideReference->SetSizeHints(-1,-1);
m_pCheckBox_PitchLinkInitialFinal = S.Id(ID_CHECKBOX_PITCH_LINKINITIALFINAL)
.AddCheckBox(_("Link Initial/Final"), wxT("false"));
}
S.EndHorizontalLay();
}
S.EndStatic();
// Pitch Start
S.StartStatic(_("Initial Pitch Shift"));
{
S.StartMultiColumn(2, wxCENTER);
{
m_pTextCtrl_PitchHalfStepsStart = S.Id(ID_TEXT_PITCH_HALFSTEPS_START)
.AddTextBox(_("(semitones) [-12 to 12]:"), wxT(""), 12);
m_pTextCtrl_PitchHalfStepsStart->SetValidator(numvld);
m_pTextCtrl_PitchPercentChangeStart = S.Id(ID_TEXT_PITCH_PERCENTCHANGE_START)
.AddTextBox(_("(%) [-50 to 100]:"), wxT(""), 12);
m_pTextCtrl_PitchPercentChangeStart->SetValidator(numvld);
}
S.EndMultiColumn();
}
S.EndStatic();
// Pitch End
S.StartStatic(_("Final Pitch Shift"));
{
S.StartMultiColumn(2, wxCENTER);
{
m_pTextCtrl_PitchHalfStepsEnd = S.Id(ID_TEXT_PITCH_HALFSTEPS_END)
.AddTextBox(_("(semitones) [-12 to 12]:"), wxT(""), 12);
m_pTextCtrl_PitchHalfStepsEnd->SetValidator(numvld);
m_pTextCtrl_PitchPercentChangeEnd = S.Id(ID_TEXT_PITCH_PERCENTCHANGE_END)
.AddTextBox(_("(%) [-50 to 100]:"), wxT(""), 12);
m_pTextCtrl_PitchPercentChangeEnd->SetValidator(numvld);
}
S.EndMultiColumn();
}
S.EndStatic();
S.EndMultiColumn();
S.StartStatic(_("Options"));
{
S.StartHorizontalLay(wxEXPAND);
{
S.SetStyle(wxSL_HORIZONTAL);
m_pCheckBox_PreAnalyze = S.Id(ID_CHECKBOX_PREANALYZE)
.AddCheckBox(wxT("Dynamic Transient Sharpening"), wxT("Dynamic Transient Sharpening"));
m_pCheckBox_LinkRatePitch = S.Id(ID_CHECKBOX_LINKRATEPITCH)
.AddCheckBox(_("Link Rate/Pitch (Resample)"), wxT("false"));
}
S.EndHorizontalLay();
}
S.EndStatic();
return;
}
@ -326,7 +453,13 @@ bool TimeScaleDialog::TransferDataToWindow()
this->Update_Text_PitchHalfStepsEnd();
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchPercentChangeEnd();
this->Update_CheckBox_PreAnalyze();
this->Update_CheckBox_LinkRatePitch();
this->Update_Choice_RateSlideType();
this->Update_Choice_PitchSlideType();
this->Update_Choice_RateSlideReference();
this->Update_Choice_PitchSlideReference();
this->Update_CheckBox_RateLinkInitialFinal();
this->Update_CheckBox_PitchLinkInitialFinal();
m_bLoopDetect = false;
@ -379,8 +512,32 @@ bool TimeScaleDialog::TransferDataFromWindow()
m_PitchPercentChangeEnd = newValue;
}
if(m_pCheckBox_PreAnalyze) {
m_PreAnalyze = m_pCheckBox_PreAnalyze->GetValue();
if(m_pCheckBox_LinkRatePitch) {
m_LinkRatePitch = m_pCheckBox_LinkRatePitch->GetValue();
}
if(m_pChoice_RateSlideType) {
m_RateSlideType = m_pChoice_RateSlideType->GetSelection();
}
if(m_pChoice_PitchSlideType) {
m_PitchSlideType = m_pChoice_PitchSlideType->GetSelection();
}
if(m_pChoice_RateSlideReference) {
m_RateSlideReference = m_pChoice_RateSlideReference->GetSelection();
}
if(m_pChoice_PitchSlideReference) {
m_PitchSlideReference = m_pChoice_PitchSlideReference->GetSelection();
}
if(m_pCheckBox_RateLinkInitialFinal) {
m_RateLinkInitialFinal = m_pCheckBox_RateLinkInitialFinal->GetValue();
}
if(m_pCheckBox_PitchLinkInitialFinal) {
m_PitchLinkInitialFinal = m_pCheckBox_PitchLinkInitialFinal->GetValue();
}
return true;
@ -395,17 +552,18 @@ bool TimeScaleDialog::CheckParameters()
(m_RatePercentChangeEnd >= RATE_PERCENTCHANGE_MIN_TEXT &&
m_RatePercentChangeEnd <= RATE_PERCENTCHANGE_MAX_TEXT)
&&
(m_PitchHalfStepsStart >= PITCH_HALFSTEPS_MIN_TEXT &&
m_PitchHalfStepsStart <= PITCH_HALFSTEPS_MAX_TEXT)
&&
(m_PitchHalfStepsEnd >= PITCH_HALFSTEPS_MIN_TEXT &&
m_PitchHalfStepsEnd <= PITCH_HALFSTEPS_MAX_TEXT)
&&
(m_PitchPercentChangeStart >= PITCH_PERCENTCHANGE_MIN_TEXT &&
m_PitchPercentChangeStart <= PITCH_PERCENTCHANGE_MAX_TEXT)
&&
(m_PitchPercentChangeEnd >= PITCH_PERCENTCHANGE_MIN_TEXT &&
m_PitchPercentChangeEnd <= PITCH_PERCENTCHANGE_MAX_TEXT);
(m_LinkRatePitch ||
((m_PitchHalfStepsStart >= PITCH_HALFSTEPS_MIN_TEXT &&
m_PitchHalfStepsStart <= PITCH_HALFSTEPS_MAX_TEXT)
&&
(m_PitchHalfStepsEnd >= PITCH_HALFSTEPS_MIN_TEXT &&
m_PitchHalfStepsEnd <= PITCH_HALFSTEPS_MAX_TEXT)
&&
(m_PitchPercentChangeStart >= PITCH_PERCENTCHANGE_MIN_TEXT &&
m_PitchPercentChangeStart <= PITCH_PERCENTCHANGE_MAX_TEXT)
&&
(m_PitchPercentChangeEnd >= PITCH_PERCENTCHANGE_MIN_TEXT &&
m_PitchPercentChangeEnd <= PITCH_PERCENTCHANGE_MAX_TEXT)));
}
// handler implementations for TimeScaleDialog
@ -423,6 +581,23 @@ void TimeScaleDialog::OnText_RatePercentChangeStart(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Slider_RatePercentChangeStart();
if(m_LinkRatePitch) {
m_PitchPercentChangeStart = m_RatePercentChangeStart;
m_PitchHalfStepsStart = PercentChangeToHalfSteps(m_PitchPercentChangeStart);
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeEnd = m_RatePercentChangeStart;
m_PitchHalfStepsEnd = m_PitchHalfStepsStart;
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
}
}
if(m_RateLinkInitialFinal) {
m_RatePercentChangeEnd = m_RatePercentChangeStart;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
@ -442,6 +617,23 @@ void TimeScaleDialog::OnText_RatePercentChangeEnd(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Slider_RatePercentChangeEnd();
if(m_LinkRatePitch) {
m_PitchPercentChangeEnd = m_RatePercentChangeEnd;
m_PitchHalfStepsEnd = PercentChangeToHalfSteps(m_PitchPercentChangeEnd);
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeStart = m_RatePercentChangeEnd;
m_PitchHalfStepsStart = m_PitchHalfStepsEnd;
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
}
}
if(m_RateLinkInitialFinal) {
m_RatePercentChangeStart = m_RatePercentChangeEnd;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
@ -458,7 +650,26 @@ void TimeScaleDialog::OnSlider_RatePercentChangeStart(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Text_RatePercentChangeStart();
if(m_LinkRatePitch) {
m_PitchPercentChangeStart = m_RatePercentChangeStart;
m_PitchHalfStepsStart = PercentChangeToHalfSteps(m_PitchPercentChangeStart);
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeEnd = m_RatePercentChangeStart;
m_PitchHalfStepsEnd = m_PitchHalfStepsStart;
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
}
}
if(m_RateLinkInitialFinal) {
m_RatePercentChangeEnd = m_RatePercentChangeStart;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
}
}
@ -472,7 +683,26 @@ void TimeScaleDialog::OnSlider_RatePercentChangeEnd(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Text_RatePercentChangeEnd();
if(m_LinkRatePitch) {
m_PitchPercentChangeEnd = m_RatePercentChangeEnd;
m_PitchHalfStepsEnd = PercentChangeToHalfSteps(m_PitchPercentChangeEnd);
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeStart = m_RatePercentChangeEnd;
m_PitchHalfStepsStart = m_PitchHalfStepsEnd;
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
}
}
if(m_RateLinkInitialFinal) {
m_RatePercentChangeStart = m_RatePercentChangeEnd;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
}
}
@ -490,6 +720,22 @@ void TimeScaleDialog::OnText_PitchHalfStepsStart(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Text_PitchPercentChangeStart();
if(m_LinkRatePitch) {
m_RatePercentChangeStart = m_PitchPercentChangeStart;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
if(m_RateLinkInitialFinal) {
m_RatePercentChangeEnd = m_PitchPercentChangeStart;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
}
}
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeEnd = m_PitchPercentChangeStart;
m_PitchHalfStepsEnd = m_PitchHalfStepsStart;
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
@ -510,6 +756,22 @@ void TimeScaleDialog::OnText_PitchHalfStepsEnd(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Text_PitchPercentChangeEnd();
if(m_LinkRatePitch) {
m_RatePercentChangeEnd = m_PitchPercentChangeEnd;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
if(m_RateLinkInitialFinal) {
m_RatePercentChangeStart = m_PitchPercentChangeEnd;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
}
}
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeStart = m_PitchPercentChangeEnd;
m_PitchHalfStepsStart = m_PitchHalfStepsEnd;
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
@ -527,11 +789,27 @@ void TimeScaleDialog::OnText_PitchPercentChangeStart(wxCommandEvent & event)
str.ToDouble(&newValue);
m_PitchPercentChangeStart = newValue;
m_PitchHalfStepsStart = PercentChangeToHalfSteps(newValue);
m_bLoopDetect = true;
this->Update_Text_PitchHalfStepsStart();
if(m_LinkRatePitch) {
m_RatePercentChangeStart = m_PitchPercentChangeStart;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
if(m_PitchLinkInitialFinal) {
m_RatePercentChangeEnd = m_PitchPercentChangeStart;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
}
}
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeEnd = m_PitchPercentChangeStart;
m_PitchHalfStepsEnd = m_PitchHalfStepsStart;
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
}
}
@ -550,16 +828,156 @@ void TimeScaleDialog::OnText_PitchPercentChangeEnd(wxCommandEvent & event)
m_bLoopDetect = true;
this->Update_Text_PitchHalfStepsEnd();
if(m_LinkRatePitch) {
m_RatePercentChangeEnd = m_PitchPercentChangeEnd;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
if(m_PitchLinkInitialFinal) {
m_RatePercentChangeStart = m_PitchPercentChangeEnd;
this->Update_Text_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeStart();
}
}
if(m_PitchLinkInitialFinal) {
m_PitchPercentChangeStart = m_PitchPercentChangeEnd;
m_PitchHalfStepsStart = m_PitchHalfStepsEnd;
this->Update_Text_PitchPercentChangeStart();
this->Update_Text_PitchHalfStepsStart();
}
m_bLoopDetect = false;
FindWindow(wxID_OK)->Enable(CheckParameters());
}
}
void TimeScaleDialog::OnCheckBox_PreAnalyze(wxCommandEvent & event)
void TimeScaleDialog::OnCheckBox_LinkRatePitch(wxCommandEvent & event)
{
if (m_pCheckBox_PreAnalyze) {
m_PreAnalyze = m_pCheckBox_PreAnalyze->GetValue();
if (m_bLoopDetect)
return;
if (m_pCheckBox_LinkRatePitch) {
m_LinkRatePitch = m_pCheckBox_LinkRatePitch->GetValue();
if(m_LinkRatePitch) {
m_bLoopDetect = true;
m_RatePercentChangeStart = m_PitchPercentChangeStart;
m_RatePercentChangeEnd = m_PitchPercentChangeEnd;
m_RateSlideType = m_PitchSlideType;
m_RateSlideReference = m_PitchSlideReference;
m_RateLinkInitialFinal = m_PitchLinkInitialFinal;
this->Update_Text_RatePercentChangeStart();
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeStart();
this->Update_Slider_RatePercentChangeEnd();
this->Update_Choice_RateSlideType();
this->Update_Choice_RateSlideReference();
this->Update_CheckBox_RateLinkInitialFinal();
m_bLoopDetect = false;
} else {
}
FindWindow(wxID_OK)->Enable(CheckParameters());
}
}
void TimeScaleDialog::OnCheckBox_RateLinkInitialFinal(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pCheckBox_RateLinkInitialFinal) {
m_RateLinkInitialFinal = m_pCheckBox_RateLinkInitialFinal->GetValue();
if(m_RateLinkInitialFinal) {
m_bLoopDetect = true;
m_RatePercentChangeEnd = m_RatePercentChangeStart;
this->Update_Text_RatePercentChangeEnd();
this->Update_Slider_RatePercentChangeEnd();
m_bLoopDetect = false;
}
}
}
void TimeScaleDialog::OnCheckBox_PitchLinkInitialFinal(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pCheckBox_PitchLinkInitialFinal) {
m_PitchLinkInitialFinal = m_pCheckBox_PitchLinkInitialFinal->GetValue();
if(m_PitchLinkInitialFinal) {
m_bLoopDetect = true;
m_PitchPercentChangeEnd = m_PitchPercentChangeStart;
m_PitchHalfStepsEnd = m_PitchHalfStepsStart;
this->Update_Text_PitchPercentChangeEnd();
this->Update_Text_PitchHalfStepsEnd();
m_bLoopDetect = false;
}
}
}
void TimeScaleDialog::OnChoice_RateSlideType(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pChoice_RateSlideType) {
m_RateSlideType = m_pChoice_RateSlideType->GetSelection();
if(m_LinkRatePitch) {
m_PitchSlideType = m_RateSlideType;
m_bLoopDetect = true;
this->Update_Choice_PitchSlideType();
m_bLoopDetect = false;
}
}
}
void TimeScaleDialog::OnChoice_PitchSlideType(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pChoice_PitchSlideType) {
m_PitchSlideType = m_pChoice_PitchSlideType->GetSelection();
if(m_LinkRatePitch) {
m_RateSlideType = m_PitchSlideType;
m_bLoopDetect = true;
this->Update_Choice_RateSlideType();
m_bLoopDetect = false;
}
}
}
void TimeScaleDialog::OnChoice_RateSlideReference(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pChoice_RateSlideReference) {
m_RateSlideReference = m_pChoice_RateSlideReference->GetSelection();
if(m_LinkRatePitch) {
m_PitchSlideReference = m_RateSlideReference;
m_bLoopDetect = true;
this->Update_Choice_PitchSlideReference();
m_bLoopDetect = false;
}
}
}
void TimeScaleDialog::OnChoice_PitchSlideReference(wxCommandEvent & event)
{
if (m_bLoopDetect)
return;
if (m_pChoice_PitchSlideReference) {
m_PitchSlideReference = m_pChoice_PitchSlideReference->GetSelection();
if(m_LinkRatePitch) {
m_RateSlideReference = m_PitchSlideReference;
m_bLoopDetect = true;
this->Update_Choice_RateSlideReference();
m_bLoopDetect = false;
}
}
}
@ -631,10 +1049,52 @@ void TimeScaleDialog::Update_Text_PitchPercentChangeEnd()
}
}
void TimeScaleDialog::Update_CheckBox_PreAnalyze()
void TimeScaleDialog::Update_CheckBox_LinkRatePitch()
{
if (m_pCheckBox_PreAnalyze) {
m_pCheckBox_PreAnalyze->SetValue(m_PreAnalyze);
if (m_pCheckBox_LinkRatePitch) {
m_pCheckBox_LinkRatePitch->SetValue(m_LinkRatePitch);
}
}
void TimeScaleDialog::Update_CheckBox_RateLinkInitialFinal()
{
if (m_pCheckBox_RateLinkInitialFinal) {
m_pCheckBox_RateLinkInitialFinal->SetValue(m_RateLinkInitialFinal);
}
}
void TimeScaleDialog::Update_CheckBox_PitchLinkInitialFinal()
{
if (m_pCheckBox_PitchLinkInitialFinal) {
m_pCheckBox_PitchLinkInitialFinal->SetValue(m_PitchLinkInitialFinal);
}
}
void TimeScaleDialog::Update_Choice_RateSlideType()
{
if (m_pChoice_RateSlideType) {
m_pChoice_RateSlideType->SetSelection(m_RateSlideType);
}
}
void TimeScaleDialog::Update_Choice_PitchSlideType()
{
if (m_pChoice_PitchSlideType) {
m_pChoice_PitchSlideType->SetSelection(m_PitchSlideType);
}
}
void TimeScaleDialog::Update_Choice_RateSlideReference()
{
if (m_pChoice_RateSlideReference) {
m_pChoice_RateSlideReference->SetSelection(m_RateSlideReference);
}
}
void TimeScaleDialog::Update_Choice_PitchSlideReference()
{
if (m_pChoice_PitchSlideReference) {
m_pChoice_PitchSlideReference->SetSelection(m_PitchSlideReference);
}
}

View File

@ -20,9 +20,13 @@
#include <wx/intl.h>
#include <wx/dialog.h>
#include <wx/slider.h>
#include <wx/choice.h>
class wxString;
class wxArrayString;
class wxTextCtrl;
class wxCheckBox;
class wxChoice;
class EffectTimeScale : public EffectSBSMS {
@ -63,7 +67,13 @@ class EffectTimeScale : public EffectSBSMS {
double m_PitchHalfStepsEnd;
double m_PitchPercentChangeStart;
double m_PitchPercentChangeEnd;
bool m_PreAnalyze;
int m_RateSlideType;
int m_PitchSlideType;
int m_RateSlideReference;
int m_PitchSlideReference;
bool m_LinkRatePitch;
bool m_RateLinkInitialFinal;
bool m_PitchLinkInitialFinal;
friend class TimeScaleDialog;
};
@ -74,61 +84,92 @@ class EffectTimeScale : public EffectSBSMS {
class TimeScaleDialog:public EffectDialog {
public:
TimeScaleDialog(EffectTimeScale * effect,
wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
TimeScaleDialog(EffectTimeScale * effect,
wxWindow * parent);
void PopulateOrExchange(ShuttleGui & S);
bool TransferDataToWindow();
bool TransferDataFromWindow();
private:
// handlers
void OnText_RatePercentChangeStart(wxCommandEvent & event);
void OnText_RatePercentChangeEnd(wxCommandEvent & event);
void OnText_PitchPercentChangeStart(wxCommandEvent & event);
void OnText_PitchPercentChangeEnd(wxCommandEvent & event);
void OnText_PitchHalfStepsStart(wxCommandEvent & event);
void OnText_PitchHalfStepsEnd(wxCommandEvent & event);
void OnSlider_RatePercentChangeStart(wxCommandEvent & event);
void OnSlider_RatePercentChangeEnd(wxCommandEvent & event);
void OnCheckBox_PreAnalyze(wxCommandEvent & event);
// helper fns
bool CheckParameters();
void Update_Text_RatePercentChangeStart();
void Update_Text_RatePercentChangeEnd();
void Update_Text_PitchPercentChangeStart();
void Update_Text_PitchPercentChangeEnd();
void Update_Text_PitchHalfStepsStart();
void Update_Text_PitchHalfStepsEnd();
void Update_Slider_RatePercentChangeStart();
void Update_Slider_RatePercentChangeEnd();
void Update_CheckBox_PreAnalyze();
// handlers
void OnText_RatePercentChangeStart(wxCommandEvent & event);
void OnText_RatePercentChangeEnd(wxCommandEvent & event);
void OnText_PitchPercentChangeStart(wxCommandEvent & event);
void OnText_PitchPercentChangeEnd(wxCommandEvent & event);
void OnText_PitchHalfStepsStart(wxCommandEvent & event);
void OnText_PitchHalfStepsEnd(wxCommandEvent & event);
void OnSlider_RatePercentChangeStart(wxCommandEvent & event);
void OnSlider_RatePercentChangeEnd(wxCommandEvent & event);
void OnCheckBox_LinkRatePitch(wxCommandEvent & event);
void OnChoice_RateSlideType(wxCommandEvent & event);
void OnChoice_PitchSlideType(wxCommandEvent & event);
void OnChoice_RateSlideReference(wxCommandEvent & event);
void OnChoice_PitchSlideReference(wxCommandEvent & event);
void OnCheckBox_RateLinkInitialFinal(wxCommandEvent & event);
void OnCheckBox_PitchLinkInitialFinal(wxCommandEvent & event);
void OnPreview(wxCommandEvent & event);
// helper fns
bool CheckParameters();
void Update_Text_RatePercentChangeStart();
void Update_Text_RatePercentChangeEnd();
void Update_Text_PitchPercentChangeStart();
void Update_Text_PitchPercentChangeEnd();
void Update_Text_PitchHalfStepsStart();
void Update_Text_PitchHalfStepsEnd();
void Update_Slider_RatePercentChangeStart();
void Update_Slider_RatePercentChangeEnd();
void Update_CheckBox_LinkRatePitch();
void Update_Choice_RateSlideType();
void Update_Choice_PitchSlideType();
void Update_Choice_RateSlideReference();
void Update_Choice_PitchSlideReference();
void Update_CheckBox_RateLinkInitialFinal();
void Update_CheckBox_PitchLinkInitialFinal();
private:
EffectTimeScale *mEffect;
bool m_bLoopDetect;
// controls
wxTextCtrl *m_pTextCtrl_RatePercentChangeStart;
wxTextCtrl *m_pTextCtrl_RatePercentChangeEnd;
wxSlider *m_pSlider_RatePercentChangeStart;
wxSlider *m_pSlider_RatePercentChangeEnd;
wxTextCtrl *m_pTextCtrl_PitchHalfStepsStart;
wxTextCtrl *m_pTextCtrl_PitchHalfStepsEnd;
wxTextCtrl *m_pTextCtrl_PitchPercentChangeStart;
wxTextCtrl *m_pTextCtrl_PitchPercentChangeEnd;
wxCheckBox *m_pCheckBox_PreAnalyze;
public:
EffectTimeScale *mEffect;
bool m_bLoopDetect;
wxArrayString rateSlideTypes;
wxArrayString pitchSlideTypes;
wxArrayString rateSlideReferences;
wxArrayString pitchSlideReferences;
// controls
wxTextCtrl *m_pTextCtrl_RatePercentChangeStart;
wxTextCtrl *m_pTextCtrl_RatePercentChangeEnd;
wxSlider *m_pSlider_RatePercentChangeStart;
wxSlider *m_pSlider_RatePercentChangeEnd;
wxTextCtrl *m_pTextCtrl_PitchHalfStepsStart;
wxTextCtrl *m_pTextCtrl_PitchHalfStepsEnd;
wxTextCtrl *m_pTextCtrl_PitchPercentChangeStart;
wxTextCtrl *m_pTextCtrl_PitchPercentChangeEnd;
wxCheckBox *m_pCheckBox_LinkRatePitch;
wxChoice *m_pChoice_RateSlideType;
wxChoice *m_pChoice_PitchSlideType;
wxChoice *m_pChoice_RateSlideReference;
wxChoice *m_pChoice_PitchSlideReference;
wxCheckBox *m_pCheckBox_RateLinkInitialFinal;
wxCheckBox *m_pCheckBox_PitchLinkInitialFinal;
double m_RatePercentChangeStart;
double m_RatePercentChangeEnd;
double m_PitchHalfStepsStart;
double m_PitchHalfStepsEnd;
double m_PitchPercentChangeStart;
double m_PitchPercentChangeEnd;
bool m_PreAnalyze;
bool m_LinkRatePitch;
int m_RateSlideType;
int m_PitchSlideType;
int m_RateSlideReference;
int m_PitchSlideReference;
bool m_RateLinkInitialFinal;
bool m_PitchLinkInitialFinal;
friend class EffectTimeScale;
private:
DECLARE_EVENT_TABLE()
};

View File

@ -10,7 +10,8 @@
\file TimeWarper.cpp
\brief Contains definitions for IdentityTimeWarper, ShiftTimeWarper,
LinearTimeWarper, LogarithmicTimeWarper classes
LinearTimeWarper, LogarithmicTimeWarper, QuadraticTimeWarper,
Geometric TimeWarper classes
*//*******************************************************************/
@ -33,14 +34,14 @@ double LinearTimeWarper::Warp(double originalTime) const
return originalTime*mScale + mShift;
}
double LogarithmicTimeWarper::Warp(double originalTime) const
double LinearInputRateTimeWarper::Warp(double originalTime) const
{
double rate = mRateWarper.Warp(originalTime);
return mTStart + mScale*log(rate/mRStart);
}
LogarithmicTimeWarper::LogarithmicTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
LinearInputRateTimeWarper::LinearInputRateTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mRateWarper(tStart, rStart, tEnd, rEnd), mRStart(rStart),
mTStart(tStart), mScale((tEnd-tStart)/(rEnd-rStart))
{
@ -48,6 +49,91 @@ LogarithmicTimeWarper::LogarithmicTimeWarper(double tStart, double tEnd,
wxASSERT(tStart < tEnd);
}
double LinearOutputRateTimeWarper::Warp(double originalTime) const
{
double scaledTime = mTimeWarper.Warp(originalTime);
return mTStart + mScale*(sqrt(mC1 + scaledTime * mC2) - mRStart);
}
LinearOutputRateTimeWarper::LinearOutputRateTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mTimeWarper(tStart, 0.0, tEnd, 1.0),
mRStart(rStart), mTStart(tStart),
mScale(2.0*(tEnd-tStart)/(rEnd*rEnd-rStart*rStart)),
mC1(rStart*rStart), mC2(rEnd*rEnd-rStart*rStart)
{
wxASSERT(rStart != rEnd);
wxASSERT(rStart > 0.0);
wxASSERT(rEnd > 0.0);
wxASSERT(tStart < tEnd);
}
double LinearInputStretchTimeWarper::Warp(double originalTime) const
{
double scaledTime = mTimeWarper.Warp(originalTime);
return mTStart + mC1 * scaledTime * (1.0 + mC2 * scaledTime);
}
LinearInputStretchTimeWarper::LinearInputStretchTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mTimeWarper(tStart, 0.0, tEnd, 1.0), mTStart(tStart),
mC1((tEnd-tStart)/rStart), mC2(0.5*(rStart/rEnd - 1.0))
{
wxASSERT(rStart > 0.0);
wxASSERT(rEnd > 0.0);
wxASSERT(tStart < tEnd);
}
double LinearOutputStretchTimeWarper::Warp(double originalTime) const
{
double scaledTime = mTimeWarper.Warp(originalTime);
return mTStart + mC1 * (pow(mC2, scaledTime) - 1.0);
}
LinearOutputStretchTimeWarper::LinearOutputStretchTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mTimeWarper(tStart, 0.0, tEnd, 1.0), mTStart(tStart),
mC1((tEnd-tStart)/(rStart*log(rStart/rEnd))), mC2(rStart/rEnd)
{
wxASSERT(rStart != rEnd);
wxASSERT(rStart > 0.0);
wxASSERT(rEnd > 0.0);
wxASSERT(tStart < tEnd);
}
double GeometricInputTimeWarper::Warp(double originalTime) const
{
double scaledTime = mTimeWarper.Warp(originalTime);
return mTStart + mScale*(pow(mRatio,scaledTime) - 1.0);
}
GeometricInputTimeWarper::GeometricInputTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mTimeWarper(tStart, 0.0, tEnd, 1.0), mTStart(tStart),
mScale((tEnd-tStart)/(log(rStart/rEnd)*rStart)), mRatio(rStart/rEnd)
{
wxASSERT(rStart != rEnd);
wxASSERT(rStart > 0.0);
wxASSERT(rEnd > 0.0);
wxASSERT(tStart < tEnd);
}
double GeometricOutputTimeWarper::Warp(double originalTime) const
{
double scaledTime = mTimeWarper.Warp(originalTime);
return mTStart + mScale*log(mC0 * scaledTime + 1.0);
}
GeometricOutputTimeWarper::GeometricOutputTimeWarper(double tStart, double tEnd,
double rStart, double rEnd)
: mTimeWarper(tStart, 0.0, tEnd, 1.0), mTStart(tStart),
mScale((tEnd-tStart)/(rEnd-rStart)), mC0((rEnd-rStart)/rStart)
{
wxASSERT(rStart > 0.0);
wxASSERT(rEnd > 0.0);
wxASSERT(tStart < tEnd);
}
StepTimeWarper::StepTimeWarper(double tStep, double offset)
: mTStep(tStep), mOffset(offset)
{ }

View File

@ -10,7 +10,9 @@
\file TimeWarper.h
\brief Contains declarations for TimeWarper, IdentityTimeWarper,
ShiftTimeWarper, LinearTimeWarper, LogarithmicTimeWarper classes
ShiftTimeWarper, LinearTimeWarper, LinearInputRateSlideTimeWarper,
LinearOutputRateSlideTimeWarper, LinearInputInverseRateTimeWarper,
GeometricInputRateTimeWarper, GeometricOutputRateTimeWarper classes
\class TimeWarper
\brief Transforms one point in time to another point. For example, a time
@ -26,8 +28,20 @@ split points in the input.
\class LinearTimeWarper
\brief Linear scaling, initialised by giving two points on the line
\class LogarithmicTimeWarper
\brief TimeScale - rate varies linearly, so time changes logarithmically.
\class LinearInputRateTimeWarper
\brief TimeScale - rate varies linearly with input
\class LinearOutputRateTimeWarper
\brief TimeScale - rate varies linearly with output
\class LinearInputInverseRateTimeWarper
\brief TimeScale - inverse rate varies linearly with input
\class GeometricInputRateTimeWarper
\brief TimeScale - rate varies geometrically with input
\class GeometricOutputRateTimeWarper
\brief TimeScale - rate varies geometrically with output
\class StepTimeWarper
\brief Like identity but with a jump
@ -82,7 +96,7 @@ public:
virtual double Warp(double originalTime) const;
};
class LogarithmicTimeWarper : public TimeWarper
class LinearInputRateTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mRateWarper;
@ -90,8 +104,75 @@ private:
double mTStart;
double mScale;
public:
LogarithmicTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
LinearInputRateTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};
class LinearOutputRateTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mTimeWarper;
double mRStart;
double mTStart;
double mScale;
double mC1;
double mC2;
public:
LinearOutputRateTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};
class LinearInputStretchTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mTimeWarper;
double mTStart;
double mC1;
double mC2;
public:
LinearInputStretchTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};
class LinearOutputStretchTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mTimeWarper;
double mTStart;
double mC1;
double mC2;
public:
LinearOutputStretchTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};
class GeometricInputTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mTimeWarper;
double mTStart;
double mScale;
double mRatio;
public:
GeometricInputTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};
class GeometricOutputTimeWarper : public TimeWarper
{
private:
LinearTimeWarper mTimeWarper;
double mTStart;
double mScale;
double mC0;
public:
GeometricOutputTimeWarper(double tStart, double tEnd,
double rStart, double rEnd);
virtual double Warp(double originalTime) const;
};

View File

@ -285,11 +285,11 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\..\lib-src\sbsms\src\audio.cpp"
RelativePath="..\..\..\lib-src\sbsms\src\buffer.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\buffer.cpp"
RelativePath="..\..\..\lib-src\sbsms\src\dBTable.cpp"
>
</File>
<File
@ -300,10 +300,6 @@
RelativePath="..\..\..\lib-src\sbsms\src\grain.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\peak.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\resample.cpp"
>
@ -312,6 +308,10 @@
RelativePath="..\..\..\lib-src\sbsms\src\sbsms.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\slide.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\sms.cpp"
>
@ -328,10 +328,6 @@
RelativePath="..\..\..\lib-src\sbsms\src\trackpoint.cpp"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\utils.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
@ -339,11 +335,11 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\..\..\lib-src\sbsms\src\audio.h"
RelativePath="..\..\..\lib-src\sbsms\src\buffer.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\buffer.h"
RelativePath="..\..\..\lib-src\sbsms\src\dBTable.h"
>
</File>
<File
@ -354,10 +350,6 @@
RelativePath="..\..\..\lib-src\sbsms\src\grain.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\peak.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\real.h"
>
@ -370,10 +362,18 @@
RelativePath="..\..\..\lib-src\sbsms\src\sms.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\sse.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\subband.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\synthTable.h"
>
</File>
<File
RelativePath="..\..\..\lib-src\sbsms\src\track.h"
>