Browse Source

paulstretch 2.1-0

master
Nasca Octavian PAUL 14 years ago
commit
1a9012c39a
50 changed files with 8220 additions and 0 deletions
  1. +116
    -0
      BinauralBeats.cpp
  2. +109
    -0
      BinauralBeats.h
  3. +340
    -0
      COPYING
  4. +650
    -0
      Control.cpp
  5. +127
    -0
      Control.h
  6. +233
    -0
      FreeEdit.cpp
  7. +252
    -0
      FreeEdit.h
  8. +595
    -0
      FreeEditUI.fl
  9. +933
    -0
      GUI.fl
  10. +90
    -0
      Input/AInputS.cpp
  11. +40
    -0
      Input/AInputS.h
  12. +43
    -0
      Input/InputS.h
  13. +209
    -0
      Input/MP3InputS.cpp
  14. +51
    -0
      Input/MP3InputS.h
  15. +137
    -0
      Input/VorbisInputS.cpp
  16. +45
    -0
      Input/VorbisInputS.h
  17. +243
    -0
      JAaudiooutput.cpp
  18. +34
    -0
      JAaudiooutput.h
  19. +51
    -0
      Mutex.cpp
  20. +44
    -0
      Mutex.h
  21. +62
    -0
      Output/AOutputS.cpp
  22. +41
    -0
      Output/AOutputS.h
  23. +126
    -0
      Output/VorbisOutputS.cpp
  24. +53
    -0
      Output/VorbisOutputS.h
  25. +56
    -0
      PAaudiooutput.cpp
  26. +31
    -0
      PAaudiooutput.h
  27. +439
    -0
      Player.cpp
  28. +130
    -0
      Player.h
  29. +434
    -0
      ProcessedStretch.cpp
  30. +166
    -0
      ProcessedStretch.h
  31. +305
    -0
      Stretch.cpp
  32. +97
    -0
      Stretch.h
  33. +71
    -0
      Thread.cpp
  34. +57
    -0
      Thread.h
  35. +516
    -0
      XMLwrapper.cpp
  36. +167
    -0
      XMLwrapper.h
  37. +12
    -0
      compile_linux_fftw.sh
  38. +16
    -0
      compile_linux_fftw_jack.sh
  39. +11
    -0
      compile_linux_kissfft.sh
  40. +43
    -0
      compile_win32.sh
  41. +11
    -0
      contrib/COPYING_kiss_fft.txt
  42. +150
    -0
      contrib/_kiss_fft_guts.h
  43. +399
    -0
      contrib/kiss_fft.c
  44. +119
    -0
      contrib/kiss_fft.h
  45. +159
    -0
      contrib/kiss_fftr.c
  46. +46
    -0
      contrib/kiss_fftr.h
  47. +35
    -0
      globals.cpp
  48. +37
    -0
      globals.h
  49. +81
    -0
      readme.txt
  50. +8
    -0
      version.h

+ 116
- 0
BinauralBeats.cpp View File

@@ -0,0 +1,116 @@
/*
Copyright (C) 2008-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <math.h>
#include <stdio.h>
#include "BinauralBeats.h"

void BinauralBeatsParameters::add2XML(XMLwrapper *xml){
xml->addpar("stereo_mode",(int) stereo_mode);
xml->addparreal("mono",mono);

xml->beginbranch("FREE_EDIT");
free_edit.add2XML(xml);
xml->endbranch();
};
void BinauralBeatsParameters::getfromXML(XMLwrapper *xml){
stereo_mode=(BB_STEREO_MODE)xml->getpar("stereo_mode",(int) stereo_mode,0,2);
mono=xml->getparreal("mono",mono);

if (xml->enterbranch("FREE_EDIT")){
free_edit.getfromXML(xml);
xml->exitbranch();
};
};

//coefficients of allpass filters are found by Olli Niemitalo

const REALTYPE Hilbert::coefl[]={0.6923877778065, 0.9360654322959, 0.9882295226860, 0.9987488452737};
const REALTYPE Hilbert::coefr[]={0.4021921162426, 0.8561710882420, 0.9722909545651, 0.9952884791278};

BinauralBeats::BinauralBeats(int samplerate_){
samplerate=samplerate_;
hilbert_t=0.0;
};


void BinauralBeats::process(REALTYPE *smpsl,REALTYPE *smpsr,int nsmps,REALTYPE pos_percents){
// for (int i=0;i<nsmps;i++) smpsl[i]=smpsr[i]=sin(30.0*M_PI*i*2.0/nsmps)*0.4;
//printf(" enabled %d\n",pars.free_edit.get_enabled());
if (pars.free_edit.get_enabled()){
float mono=pars.mono*0.5;
for (int i=0;i<nsmps;i++){
REALTYPE inl=smpsl[i];
REALTYPE inr=smpsr[i];
REALTYPE outl=inl*(1.0-mono)+inr*mono;
REALTYPE outr=inr*(1.0-mono)+inl*mono;

smpsl[i]=outl;
smpsr[i]=outr;
};

REALTYPE freq=pars.free_edit.get_value(pos_percents);


// freq=300;//test

freq*=0.5;//half down for left, half up for right
for (int i=0;i<nsmps;i++){
hilbert_t=fmod(hilbert_t+freq/samplerate,1.0);
REALTYPE h1=0,h2=0;
hl.process(smpsl[i],h1,h2);

REALTYPE x=hilbert_t*2.0*M_PI;
REALTYPE m1=h1*cos(x);
REALTYPE m2=h2*sin(x);
REALTYPE outl1=m1+m2;
REALTYPE outl2=m1-m2;


h1=0,h2=0;
hr.process(smpsr[i],h1,h2);

m1=h1*cos(x);
m2=h2*sin(x);
REALTYPE outr1=m1-m2;
REALTYPE outr2=m1+m2;

switch(pars.stereo_mode){
case SM_LEFT_RIGHT:
smpsl[i]=outl2;
smpsr[i]=outr2;
break;
case SM_RIGHT_LEFT:
smpsl[i]=outl1;
smpsr[i]=outr1;
break;
case SM_SYMMETRIC:
smpsl[i]=(outl1+outr1)*0.5;
smpsr[i]=(outl2+outr2)*0.5;
break;
};


};

};
};


+ 109
- 0
BinauralBeats.h View File

@@ -0,0 +1,109 @@
/*
Copyright (C) 2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef BINAURAL_BEATS
#define BINAURAL_BEATS
#include "FreeEdit.h"

#include "globals.h"

class AP{//allpass
public:
AP(REALTYPE a_=0.5){
in1=in2=out1=out2=0.0;
set(a_);
};
REALTYPE process(REALTYPE in){
REALTYPE out=a*(in+out2)-in2;
in2=in1;in1=in;
out2=out1;out1=out;

return out;
};
REALTYPE set(REALTYPE a_){
a=a_*a_;
};
private:
REALTYPE in1,in2,out1,out2;
REALTYPE a;
};



class Hilbert{
public:
Hilbert(){
for (int i=0;i<N;i++){
apl[i].set(coefl[i]);
apr[i].set(coefr[i]);
};
oldl=0.0;
};
void process(REALTYPE in, REALTYPE &out1, REALTYPE &out2){
out1=oldl;
out2=in;

for (int i=0;i<N;i++){
out1=apl[i].process(out1);
out2=apr[i].process(out2);
};


oldl=in;
};

private:
static const int N=4;
static const REALTYPE coefl[];
static const REALTYPE coefr[];
AP apl[N],apr[N];
REALTYPE oldl;
};

enum BB_STEREO_MODE{
SM_LEFT_RIGHT=0,
SM_RIGHT_LEFT=1,
SM_SYMMETRIC=2
};

struct BinauralBeatsParameters{
BinauralBeatsParameters(){
stereo_mode=SM_LEFT_RIGHT;
mono=0.5;
};

BB_STEREO_MODE stereo_mode;
float mono;
FreeEdit free_edit;
void add2XML(XMLwrapper *xml);
void getfromXML(XMLwrapper *xml);
};

class BinauralBeats{
public:
BinauralBeats(int samplerate_);
void process(REALTYPE *smpsl,REALTYPE *smpsr,int nsmps,REALTYPE pos_percents);
BinauralBeatsParameters pars;
private:
int samplerate;
REALTYPE hilbert_t;
Hilbert hl,hr;
};

#endif

+ 340
- 0
COPYING View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.

When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.

We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.

b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.

c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,

b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,

c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA


Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.

<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

+ 650
- 0
Control.cpp View File

@@ -0,0 +1,650 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdlib.h>
#include <FL/Fl.H>
#include "globals.h"
#include "Control.h"
#include "XMLwrapper.h"
using namespace std;

Control::Control(){
player=new Player();
player->start();

wavinfo.samplerate=44100;
wavinfo.nsamples=0;
wavinfo.intype=FILE_WAV;
wav32bit=false;

process.bufsize=16384;
process.stretch=4.0;
/// process.transient.enable=false;
/// process.transient.amount=0.5;

seek_pos=0.0;
window_type=W_HANN;
info.render_percent=-1.0;
info.cancel_render=false;
volume=1.0;


gui_sliders.fftsize_s=0.5;
gui_sliders.stretch_s=0.5;
gui_sliders.mode_s=0;


///#warning test
/// process.transient.enable=true;
};

Control::~Control(){
// delete player; face crash daca il las
};
///void Control::pre_analyse_whole_audio(InputS *ai){
/// int inbufsize=1024;
/// int readsize=inbufsize/2;
///
/// short int *inbuf_i=new short int[readsize*2];
///
///// REALTYPE *inbuf_f=new REALTYPE[readsize];
///// for (int i=0;i<readsize;i++) inbuf_f[i]=0.0;
///
/// REALTYPE *processbuf=new REALTYPE[inbufsize];
/// for (int i=0;i<inbufsize;i++) processbuf[i]=0.0;
///
/// FFT *infft=new FFT(inbufsize);
///
/// int k=0;
/// int fftsize=inbufsize/2;
/// REALTYPE *oldfreq=new REALTYPE[fftsize];
/// for (int i=0;i<fftsize;i++) oldfreq[i]=0.0;
/// REALTYPE oldsumstart=0.0;
/// int transient_data_n=0;
/// int transient_data_max_n=10000;
/// REALTYPE *transient_data=new REALTYPE [transient_data_max_n];
/// while(!ai->eof){
/// float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples;
///
/// int readed=ai->read(readsize,inbuf_i);
/// if (readed!=readsize) break;//do not process the last buffer from the audiofile
/// const float inv_32768=1.0/32768.0;
///
/// for (int i=0;i<inbufsize-readed;i++){
/// processbuf[i]=processbuf[i+readed];
/// };
/// for (int i=0;i<readed;i++) {
/// processbuf[i+inbufsize-readed]=(inbuf_i[i*2]*inv_32768+inbuf_i[i*2+1]*inv_32768);
/// };
///
///
/// for (int i=0;i<inbufsize;i++) infft->smp[i]=processbuf[i];
///
///
/// infft->applywindow(W_HAMMING);
/// infft->smp2freq();
/// infft->freq[0]=0;
/// REALTYPE *freq=infft->freq;
///
/// REALTYPE sumstart=0.0;
/// for (int i=0;i<fftsize;i++){
/// REALTYPE x=freq[i]-oldfreq[i];
/// if (x>0) sumstart+=x;
/// };
/// sumstart/=fftsize;
/// const REALTYPE a=0.1;
/// oldsumstart=oldsumstart*(1.0-a)+sumstart*a;
/// sumstart-=1.5*oldsumstart;
/// if (sumstart<0.0) sumstart=0.0;
///
/// transient_data[transient_data_n]=sumstart;
/// transient_data_n++;
/// if (transient_data_n>=transient_data_max_n){
/// transient_data_max_n+=100000;
/// REALTYPE *new_transient_data=new REALTYPE[transient_data_max_n];
/// for (int i=0;i<transient_data_n;i++) new_transient_data[i]=transient_data[i];
/// delete [] transient_data;
/// transient_data=new_transient_data;
/// };
///
/// for (int i=0;i<fftsize;i++) oldfreq[i]=freq[i];
/// };
/// ppar.set_transient_data(transient_data_n,transient_data);
/// delete infft;
/// delete []transient_data;
///
/// delete []oldfreq;
/// delete [] inbuf_i;
/// //delete [] inbuf_f;
/// delete [] processbuf;
///};

bool Control::set_input_filename(string filename,FILE_TYPE intype){
InputS *ai=NULL;
if (intype==FILE_VORBIS) ai=new VorbisInputS;
if (intype==FILE_MP3) ai=new MP3InputS;
if (intype==FILE_WAV) ai=new AInputS;
if (!ai) return false;
wavinfo.filename=filename;
wavinfo.intype=intype;
bool result=ai->open(wavinfo.filename);
if (result) {
wavinfo.samplerate=ai->info.samplerate;
wavinfo.nsamples=ai->info.nsamples;
/// if (process.transient.enable) {
/// pre_analyse_whole_audio(ai);
/// };

delete ai;
}else{
wavinfo.filename="";
wavinfo.samplerate=0;
wavinfo.nsamples=0;
delete ai;
};
return result;
};

string Control::get_input_filename(){
return wavinfo.filename;
};
string Control::get_input_filename_and_info(){
int seconds=wavinfo.nsamples/wavinfo.samplerate;
const int size=200;
char tmp[size];tmp[size-1]=0;
snprintf(tmp,size-1," ( samplerate=%d; duration=%02d:%02d:%02d )",wavinfo.samplerate,seconds/3600,(seconds/60)%60,seconds%60);

string filename=wavinfo.filename;
int len=filename.length();
if (len>70)filename=filename.substr(0,25)+"..."+filename.substr(len-35);
return filename+tmp;
};
/*string Control::get_recommanded_output_filename(){
return "none";
};
*/


std::string Control::get_stretch_info(){
const int size=200;
char tmp[size];tmp[size-1]=0;

if (wavinfo.nsamples==0) return "Stretch: ";


double realduration=wavinfo.nsamples/wavinfo.samplerate*process.stretch;

if (realduration>(365.25*86400.0*1.0e12)){//more than 1 trillion years
double duration=(realduration/(365.25*86400.0*1.0e12));//my
snprintf(tmp,size,"Stretch: %.7gx (%g trillion years)",process.stretch,duration);
return tmp;
};
if (realduration>(365.25*86400.0*1.0e9)){//more than 1 billion years
double duration=(realduration/(365.25*86400.0*1.0e9));//my
snprintf(tmp,size,"Stretch: %.7gx (%g billion years)",process.stretch,duration);
return tmp;
};
if (realduration>(365.25*86400.0*1.0e6)){//more than 1 million years
double duration=(realduration/(365.25*86400.0*1.0e6));//my
snprintf(tmp,size,"Stretch: %.7gx (%g million years)",process.stretch,duration);
return tmp;
};
if (realduration>(365.25*86400.0*2000.0)){//more than two millenniums
int duration=(int)(realduration/(365.25*86400.0));//years
int years=duration%1000;
int milleniums=duration/1000;

char stryears[size];stryears[0]=0;
if (years!=0){
if (years==1) snprintf(stryears,size," 1 year");
else snprintf(stryears,size," %d years",years);
};
snprintf(tmp,size,"Stretch: %.7gx (%d milleniums%s)",process.stretch,milleniums,stryears);
return tmp;
};
if (realduration>(365.25*86400.0)){//more than 1 year
int duration=(int) (realduration/3600.0);//hours
int hours=duration%24;
int days=(duration/24)%365;
int years=duration/(365*24);

char stryears[size];stryears[0]=0;
if (years==1) snprintf(stryears,size,"1 year ");
else snprintf(stryears,size,"%d years ",years);

char strdays[size];strdays[0]=0;
if (days>0){
if (days==1) snprintf(strdays,size,"1 day");
else snprintf(strdays,size,"%d days",days);
};
if (years>=10) hours=0;
char strhours[size];strhours[0]=0;
if (hours>0){
snprintf(strhours,size," %d h",hours);
};

snprintf(tmp,size,"Stretch: %.7gx (%s%s%s)",process.stretch,stryears,strdays,strhours);
return tmp;
}else{//less than 1 year
int duration=(int)(realduration);//seconds

char strdays[size];strdays[0]=0;
int days=duration/86400;
if (days>0){
if (days==1) snprintf(strdays,size,"1 day ");
else snprintf(strdays,size,"%d days ",duration/86400);
};
REALTYPE stretch=process.stretch;
if (stretch>=1.0){
stretch=((int) (stretch*100.0))*0.01;
};
snprintf(tmp,size,"Stretch: %.7gx (%s%.2d:%.2d:%.2d)",
stretch,strdays,(duration/3600)%24,(duration/60)%60,duration%60);
return tmp;
};
return "";
};

string Control::get_fftsize_info(){
const int size=200;
char tmp[size];tmp[size-1]=0;

string fftsizelabel;
fftsizelabel+="Window size (samples): ";

if (wavinfo.nsamples==0) return fftsizelabel;
fftsizelabel+=getfftsizestr(process.bufsize);

return fftsizelabel;
};

string Control::get_fftresolution_info(){
string resolution="Resolution: ";
if (wavinfo.nsamples==0) return resolution;

//todo: unctime and uncfreq are correct computed? Need to check later.
REALTYPE unctime=process.bufsize/(REALTYPE)wavinfo.samplerate*sqrt(2.0);
REALTYPE uncfreq=1.0/unctime*sqrt(2.0);
char tmp[100];
snprintf(tmp,100,"%.5g seconds",unctime);resolution+=tmp;
snprintf(tmp,100," (%.5g Hz)",uncfreq);resolution+=tmp;
return resolution;
};


void Control::startplay(bool bypass){
if ((!player->info.playing)||(player->info.samplerate!=wavinfo.samplerate)){
stopplay();
sleep(200);
#ifdef HAVE_JACK
JACKaudiooutputinit(player,wavinfo.samplerate);
#else
PAaudiooutputinit(player,wavinfo.samplerate);
#endif
};
if (wavinfo.filename!="") player->startplay(wavinfo.filename,seek_pos,process.stretch,process.bufsize,wavinfo.intype,bypass,&ppar,&bbpar);
// sleep(100);
// update_process_parameters();
};
void Control::stopplay(){
player->stop();
player->seek(0.0);
seek_pos=0;
#ifdef HAVE_JACK
JACKclose();
#else
PAfinish();
#endif
};
void Control::pauseplay(){
player->pause();
};

void Control::freezeplay(){
player->freeze();
};

void Control::set_volume(REALTYPE vol){
volume=vol;
player->set_volume(vol);
};


void Control::set_seek_pos(REALTYPE x){
seek_pos=x;
player->seek(x);
};
REALTYPE Control::get_seek_pos(){
if (player->getmode()==Player::MODE_PLAY) seek_pos=player->info.position;
return seek_pos;
};


void Control::set_stretch_controls(double stretch_s,int mode,double fftsize_s){
gui_sliders.stretch_s=stretch_s;
gui_sliders.mode_s=mode;
gui_sliders.fftsize_s=fftsize_s;

double stretch=1.0;
switch(mode){
case 0:
stretch_s=pow(stretch_s,1.2);
stretch=pow(10.0,stretch_s*4.0);
break;
case 1:
stretch_s=pow(stretch_s,1.5);
stretch=pow(10.0,stretch_s*18.0);
break;
case 2:
stretch=1.0/pow(10.0,stretch_s*3.0);
if (stretch<0.1) stretch=0.1;
break;
};


fftsize_s=pow(fftsize_s,1.5);
double tmp=1.0;
if (mode==2) tmp=1.0/stretch;
int bufsize=(int)(pow(2.0,fftsize_s*12.0)*512.0*tmp);

bufsize=optimizebufsize(bufsize);

process.stretch=stretch;
process.bufsize=bufsize;

};

double Control::get_stretch_control(double stretch,int mode){
double result=1.0;
switch(mode){
case 0:
if (stretch<1.0) return -1;
stretch=(log(stretch)/log(10))*0.25;
result=pow(stretch,1.0/1.2);
break;
case 1:
if (stretch<1.0) return -1;
stretch=(log(stretch)/log(10))/18.0;
result=pow(stretch,1.0/1.5);
break;
case 2:
if (stretch>1.0) return -1;
result=3.0/(log(stretch)/log(10));
break;
};
return result;
};


void Control::update_player_stretch(){
player->setrap(process.stretch);
};


int abs_val(int x){
if (x<0) return -x;
else return x;
};


int Control::get_optimized_updown(int n,bool up){
int orig_n=n;
while(true){
n=orig_n;
#ifndef KISSFFT
while (!(n%11)) n/=11;
while (!(n%7)) n/=7;
#endif
while (!(n%5)) n/=5;
while (!(n%3)) n/=3;
while (!(n%2)) n/=2;
if (n<2) break;
if (up) orig_n++;
else orig_n--;
if (orig_n<4) return 4;
};
return orig_n;
};
int Control::optimizebufsize(int n){
int n1=get_optimized_updown(n,false);
int n2=get_optimized_updown(n,true);
if ((n-n1)<(n2-n)) return n1;
else return n2;
};



void Control::set_window_type(FFTWindow window){
window_type=window;
if (player) player->set_window_type(window);
};


string Control::Render(string inaudio,string outaudio,FILE_TYPE outtype,FILE_TYPE intype,REALTYPE pos1,REALTYPE pos2){
if (pos2<pos1){
REALTYPE tmp=pos2;
pos2=pos1;
pos1=tmp;
};
InputS *ai=NULL;
switch(intype){
case FILE_VORBIS:ai=new VorbisInputS;
break;
case FILE_MP3:ai=new MP3InputS;
break;
default:ai=new AInputS;
};
AOutputS ao;
VorbisOutputS vorbisout;
info.cancel_render=false;
if (!ai->open(inaudio)){
return "Error: Could not open audio file (or file format not recognized) :"+inaudio;
};
BinauralBeats bb(ai->info.samplerate);
bb.pars=bbpar;
if (outtype==FILE_WAV) ao.newfile(outaudio,ai->info.samplerate,wav32bit);
if (outtype==FILE_VORBIS) vorbisout.newfile(outaudio,ai->info.samplerate);

ai->seek(pos1);

int inbufsize=process.bufsize;

if (inbufsize<32) inbufsize=32;
short int *inbuf_i=new short int[inbufsize*4];
int outbufsize;
struct{
REALTYPE *l,*r;
}inbuf;
ProcessedStretch *stretchl=new ProcessedStretch(process.stretch,inbufsize,window_type,false,ai->info.samplerate,1);
ProcessedStretch *stretchr=new ProcessedStretch(process.stretch,inbufsize,window_type,false,ai->info.samplerate,2);
stretchl->set_parameters(&ppar);
stretchr->set_parameters(&ppar);

outbufsize=stretchl->out_bufsize;
int *outbuf=new int[outbufsize*2];

int poolsize=stretchl->poolsize;

inbuf.l=new REALTYPE[poolsize];
inbuf.r=new REALTYPE[poolsize];
for (int i=0;i<poolsize;i++) inbuf.l[i]=inbuf.r[i]=0.0;

int readsize=0;
const int pause_max_write=65536;
int pause_write=0;
bool firstbuf=true;
while(!ai->eof){
float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples;
if (firstbuf){
readsize=stretchl->get_nsamples_for_fill();
firstbuf=false;
}else{
readsize=stretchl->get_nsamples(in_pos*100.0);
};
int readed=0;
if (readsize!=0) readed=ai->read(readsize,inbuf_i);
for (int i=0;i<readed;i++) {
inbuf.l[i]=inbuf_i[i*2]/32768.0;
inbuf.r[i]=inbuf_i[i*2+1]/32768.0;
};
stretchl->process(inbuf.l,readed);
stretchr->process(inbuf.r,readed);
bb.process(stretchl->out_buf,stretchr->out_buf,outbufsize,in_pos*100.0);
for (int i=0;i<outbufsize;i++) {
stretchl->out_buf[i]*=volume;
stretchr->out_buf[i]*=volume;
};
if (outtype==FILE_WAV){
for (int i=0;i<outbufsize;i++) {
REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i];
if (l<-1.0) l=-1.0;
else if (l>1.0) l=1.0;
if (r<-1.0) r=-1.0;
else if (r>1.0) r=1.0;
outbuf[i*2]=(int)(l*32767.0*65536.0);
outbuf[i*2+1]=(int)(r*32767.0*65536.0);
};
ao.write(outbufsize,outbuf);
};
if (outtype==FILE_VORBIS) vorbisout.write(outbufsize,stretchl->out_buf,stretchr->out_buf);

REALTYPE totalf=ai->info.currentsample/(REALTYPE)ai->info.nsamples-pos1;
if (totalf>(pos2-pos1)) break;

info.render_percent=(totalf*100.0/(pos2-pos1+0.001));
pause_write+=outbufsize;
if (pause_write>pause_max_write){
float tmp=outbufsize/1000000.0;
if (tmp>0.1) tmp=0.1;
Fl::wait(0.01+tmp);
pause_write=0;
if (info.cancel_render) break;
};
};

delete stretchl;
delete stretchr;
delete []outbuf;
delete []inbuf_i;
delete []inbuf.l;
delete []inbuf.r;

info.render_percent=-1.0;
return "";
};



string Control::getfftsizestr(int fftsize){
int size=100;
char tmp[size];tmp[size-1]=0;
if (fftsize<1024.0) snprintf(tmp,size-1,"%d",fftsize);
else if (fftsize<(1024.0*1024.0)) snprintf(tmp,size-1,"%.4gK",fftsize/1024.0);
else if (fftsize<(1024.0*1024.0*1024.0)) snprintf(tmp,size-1,"%.4gM",fftsize/(1024.0*1024.0));
else snprintf(tmp,size-1,"%.7gG",fftsize/(1024.0*1024.0*1024.0));
return tmp;
};

void Control::update_process_parameters(){
if (player) player->set_process_parameters(&ppar,&bbpar);
};

bool Control::save_parameters(const char *filename){
XMLwrapper *xml=new XMLwrapper();
xml->beginbranch("PAULSTRETCH");
xml->beginbranch("STRETCH_PARAMETERS");
xml->beginbranch("BASE");
xml->addpar("bufsize",process.bufsize);
xml->addparreal("stretch",process.stretch);
xml->addparreal("fftsize_s",gui_sliders.fftsize_s);
xml->addparreal("stretch_s",gui_sliders.stretch_s);
xml->addpar("mode_s",gui_sliders.mode_s);
xml->addpar("window_type",window_type);
xml->addparreal("volume",volume);

xml->endbranch();
xml->beginbranch("PROCESS");
ppar.add2XML(xml);
xml->endbranch();

xml->beginbranch("BINAURAL_BEATS");
bbpar.add2XML(xml);
xml->endbranch();

xml->endbranch();
xml->endbranch();

int result=xml->saveXMLfile(filename);
delete xml;
return true;
};

bool Control::load_parameters(const char *filename){
XMLwrapper *xml=new XMLwrapper();

if (xml->loadXMLfile(filename)<0) {
delete xml;
return false;
};


if (xml->enterbranch("PAULSTRETCH")==0) {
delete xml;
return false;
};

if (xml->enterbranch("STRETCH_PARAMETERS")){
if (xml->enterbranch("BASE")){
process.bufsize=xml->getpar("bufsize",process.bufsize,16,2e9);
process.stretch=xml->getparreal("stretch",process.stretch);
gui_sliders.fftsize_s=xml->getparreal("fftsize_s",gui_sliders.fftsize_s);
gui_sliders.stretch_s=xml->getparreal("stretch_s",gui_sliders.stretch_s);
gui_sliders.mode_s=xml->getpar("mode_s",gui_sliders.mode_s,0,2);
window_type=(FFTWindow)xml->getpar("window_type",window_type,0,4);
volume=xml->getparreal("volume",1.0);
xml->exitbranch();
};

if (xml->enterbranch("PROCESS")){
ppar.getfromXML(xml);
xml->exitbranch();
};

if (xml->enterbranch("BINAURAL_BEATS")){
bbpar.getfromXML(xml);
xml->exitbranch();
};

xml->exitbranch();
};
delete xml;

set_stretch_controls(gui_sliders.stretch_s,gui_sliders.mode_s,gui_sliders.fftsize_s);
set_window_type(window_type);
set_volume(volume);
update_process_parameters();
return true;
};


+ 127
- 0
Control.h View File

@@ -0,0 +1,127 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef CONTROL_H
#define CONTROL_H

#include "globals.h"
#include "Input/AInputS.h"
#include "Input/VorbisInputS.h"
#include "Input/MP3InputS.h"
#include "Output/AOutputS.h"
#include "Output/VorbisOutputS.h"
#include "ProcessedStretch.h"
#include "Player.h"
#include "JAaudiooutput.h"
#include "PAaudiooutput.h"
#include "BinauralBeats.h"

class Control{
public:
Control();
~Control();

void UpdateControlInfo();
void startplay(bool bypass);
void stopplay();
void pauseplay();
void freezeplay();

void set_volume(REALTYPE vol);

void set_seek_pos(REALTYPE x);
REALTYPE get_seek_pos();

bool save_parameters(const char *filename);
bool load_parameters(const char *filename);

bool playing(){
return player->info.playing;
};
bool playing_eof(){
return player->info.eof;
};

bool set_input_filename(std::string filename,FILE_TYPE intype);//return false if the file cannot be opened
std::string get_input_filename();
std::string get_input_filename_and_info();
std::string get_stretch_info();
std::string get_fftsize_info();
std::string get_fftresolution_info();
double get_stretch(){
return process.stretch;
};

bool is_freeze(){
return player->is_freeze();
};

void set_stretch_controls(double stretch_s,int mode,double fftsize_s);//*_s sunt de la 0.0 la 1.0
double get_stretch_control(double stretch,int mode);
void update_player_stretch();

void set_window_type(FFTWindow window);
/// void pre_analyse_whole_audio(InputS *ai);

std::string Render(std::string inaudio,std::string outaudio,FILE_TYPE outtype,FILE_TYPE intype,
REALTYPE pos1,REALTYPE pos2);//returneaza o eroare sau un string gol (pos1,pos2 are from 0.0 to 1.0)
struct {
REALTYPE render_percent;
bool cancel_render;
}info;

ProcessParameters ppar;
BinauralBeatsParameters bbpar;
bool wav32bit;
void update_process_parameters();//pt. player
struct{
double fftsize_s,stretch_s;
int mode_s;
}gui_sliders;
FFTWindow window_type;

private:
REALTYPE volume;

int get_optimized_updown(int n,bool up);
int optimizebufsize(int bufsize);
std::string getfftsizestr(int fftsize);

struct {
int bufsize;
double stretch;
/// struct{
/// bool enable;
/// double amount;
/// } transient;
}process;

struct {
int samplerate;
int nsamples;
std::string filename;
FILE_TYPE intype;
}wavinfo;//input
REALTYPE seek_pos;

Player *player;
};

#endif


+ 233
- 0
FreeEdit.cpp View File

@@ -0,0 +1,233 @@
/*
Copyright (C) 2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdio.h>
#include <math.h>
#include "FreeEdit.h"

FreeEdit::FreeEdit(){
enabled=false;
smooth=0.0;
interp_mode=LINEAR;
npos=FREE_EDIT_MAX_POINTS;
pos=new FreeEditPos[npos];
for (int i=0;i<npos;i++){
pos[i].x=pos[i].y=0;
pos[i].enabled=false;
};
pos[0].x=0;
pos[0].y=0.5;
pos[0].enabled=true;
pos[1].x=1;
pos[1].y=0.5;
pos[1].enabled=true;
curve.data=NULL;
curve.size=0;
};

void FreeEdit::deep_copy_from(const FreeEdit &other){
enabled=other.enabled;
smooth=other.smooth;
interp_mode=other.interp_mode;
npos=other.npos;
pos=new FreeEditPos[npos];
for (int i=0;i<npos;i++){
pos[i].x=other.pos[i].x;
pos[i].y=other.pos[i].y;
pos[i].enabled=other.pos[i].enabled;
};
curve.size=other.curve.size;
if (other.curve.data&&other.curve.size){
curve.data=new REALTYPE[curve.size];
for (int i=0;i<curve.size;i++) curve.data[i]=other.curve.data[i];
}else curve.data=NULL;
extreme_x=other.extreme_x;
extreme_y=other.extreme_y;
};
FreeEdit::FreeEdit (const FreeEdit &other){
deep_copy_from(other);
};
const FreeEdit &FreeEdit::operator=(const FreeEdit &other){
if (this == &other) return *this;
deep_copy_from(other);
return *this;
};
void FreeEdit::get_curve(int datasize,REALTYPE *data,bool real_values){
int npos_used=0;
for (int i=0;i<npos;i++) if (is_enabled(i)) npos_used++;
if (!npos_used){
for (int i=0;i<datasize;i++) data[i]=(real_values?extreme_y.get_min():0.0);
return;
};

//get the enabled points
REALTYPE posx[npos_used],posy[npos_used];
int k=0;
for (int i=0;i<npos;i++){
if (is_enabled(i)){
posx[k]=get_posx(i);
posy[k]=get_posy(i);
k++;
};
};

//sort the points
for (int j=0;j<npos_used-1;j++){
for (int i=j+1;i<npos_used;i++){
if (posx[i]<posx[j]){
swap(posx[i],posx[j]);
swap(posy[i],posy[j]);
};
};
};

//generate the curve
int p1=0,p2=1;
for (int i=0;i<datasize;i++){
REALTYPE x=(REALTYPE)i/(REALTYPE)datasize;
while ((x>posx[p2])&&(p2<npos_used)){
p1=p2;
p2++;
};
REALTYPE px1=posx[p1];
REALTYPE px2=posx[p2];
REALTYPE diffx=px2-px1;
REALTYPE x0=0;
if (diffx>1e-5) x0=(x-px1)/diffx;
if (interp_mode==COSINE) x0=(1.0-cos(x0*M_PI))*0.5;
REALTYPE y=y=posy[p1]*(1.0-x0)+posy[p2]*x0;
data[i]=y;
};


//smooth the curve
if (smooth>0.01){
const int max_times=4;
REALTYPE a=exp(log(0.25)/(smooth*smooth*datasize*0.25));
if ((a<=0.0)||(a>=1.0)) return;
a=pow(a,max_times);
for (k=0;k<max_times;k++){
for (int i=1;i<datasize;i++) data[i]=data[i]*(1.0-a)+data[i-1]*a;
for (int i=datasize-2;i>=0;i--) data[i]=data[i]*(1.0-a)+data[i+1]*a;
};
};

if (real_values){
for (int i=0;i<datasize;i++) data[i]=extreme_y.coord_to_real_value(data[i]);
if (extreme_y.get_scale()==FE_DB){
for (int i=0;i<datasize;i++) data[i]=dB2rap(data[i]);
};
};

};

void FreeEdit::update_curve(int size){
if (curve.data) delete []curve.data;
if (size<2) size=2;
curve.size=size;
curve.data=new REALTYPE[size];

get_curve(curve.size,curve.data,true);

// for(int i=0;i<size;i++) printf("_%d %g\n",i,curve.data[i]);
};

REALTYPE FreeEdit::get_value(REALTYPE x){
if (!curve.data) {
return 0.0;// update_curve();
};
if (extreme_x.get_scale()==FE_LOG){
if (x<=0.0) x=1e-9;
};
// printf("%g\n",curve.data[1]);
x=extreme_x.real_value_to_coord(x);
if (x<0) x=0.0;
else if (x>1.0) x=1.0;
REALTYPE rx=x*curve.size;
REALTYPE rxh=floor(rx);
int k=(int)rxh;
REALTYPE rxl=rx-rxh;
if (k<0) k=0;
if (k>(curve.size-1)) k=curve.size-1;
int k1=k+1; if (k1>(curve.size-1)) k1=curve.size-1;
return curve.data[k]*(1.0-rxl)+curve.data[k1]*rxl;
};

void FreeEdit::add2XML(XMLwrapper *xml){
xml->addparbool("enabled",enabled);
xml->addparreal("smooth",smooth);
xml->addpar("interp_mode",interp_mode);
xml->beginbranch("POINTS");
for (int i=0;i<FREE_EDIT_MAX_POINTS;i++){
if (!pos[i].enabled) continue;
xml->beginbranch("POINT",i);
xml->addparbool("enabled",pos[i].enabled);
xml->addparreal("x",pos[i].x);
xml->addparreal("y",pos[i].y);
xml->endbranch();
};
xml->endbranch();

xml->beginbranch("EXTREME_X");
extreme_x.add2XML(xml);
xml->endbranch();

xml->beginbranch("EXTREME_Y");
extreme_y.add2XML(xml);
xml->endbranch();
};


void FreeEdit::getfromXML(XMLwrapper *xml){
enabled=xml->getparbool("enabled",enabled);
smooth=xml->getparreal("smooth",smooth);
interp_mode=(INTERP_MODE)xml->getpar("interp_mode",interp_mode,0,1);
if (xml->enterbranch("POINTS")){
for (int i=0;i<FREE_EDIT_MAX_POINTS;i++){
if (xml->enterbranch("POINT",i)){
pos[i].enabled=xml->getparbool("enabled",pos[i].enabled);
pos[i].x=xml->getparreal("x",pos[i].x);
pos[i].y=xml->getparreal("y",pos[i].y);

xml->exitbranch();
};
};
xml->exitbranch();
};

if (xml->enterbranch("EXTREME_X")){
extreme_x.getfromXML(xml);
xml->exitbranch();
};

if (xml->enterbranch("EXTREME_Y")){
extreme_y.getfromXML(xml);
xml->exitbranch();
};

update_curve();
};



+ 252
- 0
FreeEdit.h View File

@@ -0,0 +1,252 @@
/*
Copyright (C) 2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef FREEEDIT_H
#define FREEEDIT_H

#define FREE_EDIT_MAX_POINTS 50
#include <math.h>
#include <stdio.h>

#include "globals.h"
#include "XMLwrapper.h"

#define LOG_2 0.693147181
#define LOG_10 2.302585093

#define dB2rap(dB) ((exp((dB)*LOG_10/20.0)))
#define rap2dB(rap) ((20*log(rap)/LOG_10))

struct FreeEditPos{
REALTYPE x,y;
bool enabled;
};
enum FREE_EDIT_EXTREME_SCALE{
FE_LINEAR=0,
FE_LOG=1,
FE_DB=2
};
class FreeEditExtremes{
public:
FreeEditExtremes(){
init();
};
void init(REALTYPE min_=0.0,REALTYPE max_=1.0,FREE_EDIT_EXTREME_SCALE scale_=FE_LINEAR,bool lock_min_max_=false,bool lock_scale_=false){
min=min_;
max=max_;
scale=scale_;
lock_min_max=lock_min_max_;
lock_scale=lock_scale_;
correct_values();
};

//converting functions
inline REALTYPE coord_to_real_value(REALTYPE coord){//coord = 0.0 .. 1.0
REALTYPE result;
switch(scale){
case FE_LOG://log
result=exp(log(min)+coord*(log(max)-log(min)));
return result;
default://linear or dB
result=min+coord*(max-min);
return result;
};
};

inline REALTYPE real_value_to_coord(REALTYPE val){//coord = 0.0 .. 1.0
switch(scale){
case FE_LOG://log
{
REALTYPE coord=log(val/min)/log(max/min);
clamp1(coord);
return coord;
};
default://linear
{
REALTYPE diff=max-min;
REALTYPE coord;
if (fabs(diff)>0.0001) coord=(val-min)/diff;
else coord=min;
clamp1(coord);
return coord;
};
};
};

//max and min functions
void set_min(REALTYPE val){
if (lock_min_max) return;
min=val;
correct_values();
};
REALTYPE get_min(){
return min;
};
void set_max(REALTYPE val){
if (lock_min_max) return;
max=val;
correct_values();
};
REALTYPE get_max(){
return max;
};
//scale functions
FREE_EDIT_EXTREME_SCALE get_scale(){
return scale;
};
void set_scale(FREE_EDIT_EXTREME_SCALE val){
if (lock_scale) return;
scale=val;
};
void add2XML(XMLwrapper *xml){
xml->addparreal("min",min);
xml->addparreal("max",max);
};
void getfromXML(XMLwrapper *xml){
set_min(xml->getparreal("min",min));
set_max(xml->getparreal("max",max));
};
private:
inline REALTYPE clamp1(REALTYPE m){
if (m<0.0) return 0.0;
if (m>1.0) return 1.0;
return m;
};
void correct_values(){
if (scale!=FE_LOG) return;
if (min<1e-8) min=1e-8;
if (max<1e-8) max=1e-8;
};
bool lock_min_max,lock_scale;
REALTYPE min,max;
FREE_EDIT_EXTREME_SCALE scale;
};
class FreeEdit{
public:
enum INTERP_MODE{
LINEAR=0,
COSINE=1
};
FreeEdit();
FreeEdit (const FreeEdit &other);
const FreeEdit &operator=(const FreeEdit &other);
void deep_copy_from(const FreeEdit &other);

void add2XML(XMLwrapper *xml);
void getfromXML(XMLwrapper *xml);

//Enabled functions
bool get_enabled(){
return enabled;
};
void set_enabled(bool val){
enabled=val;
};

inline int get_npoints(){
return npos;
};

//manipulation functions
inline bool is_enabled(int n){
if ((n<0)||(n>=npos)) return false;
return pos[n].enabled;
};
inline void set_enabled(int n,bool enabled){
if ((n<0)||(n>=npos)) return;
pos[n].enabled=enabled;
};


inline REALTYPE get_posx(int n){
if ((n<0)||(n>=npos)) return 0.0;
return pos[n].x;
};
inline REALTYPE get_posy(int n){
if ((n<0)||(n>=npos)) return 0.0;
return pos[n].y;
};
inline void set_posx(int n,REALTYPE x){
if ((n<2)||(n>=npos)) return;//don't allow to set the x position of the first two positions
pos[n].x=clamp1(x);
};
inline void set_posy(int n,REALTYPE y){
if ((n<0)||(n>=npos)) return;
pos[n].y=clamp1(y);
};

void set_all_values(REALTYPE val){
for (int i=0;i<npos;i++){
if (pos[i].enabled) pos[i].y=extreme_y.real_value_to_coord(val);
}
};

//interpolation mode
INTERP_MODE get_interp_mode(){
return interp_mode;
};
void set_interp_mode(INTERP_MODE interp_mode_){
interp_mode=interp_mode_;
};

//smooth
REALTYPE get_smooth(){
return smooth;
};
void set_smooth(REALTYPE smooth_){
smooth=clamp1(smooth_);;
};

//getting the curve
void get_curve(int datasize,REALTYPE *data,bool real_values);

~FreeEdit(){
delete []pos;
};

//making/updating the curve
void update_curve(int size=16384);
REALTYPE get_value(REALTYPE x);

//extremes
FreeEditExtremes extreme_x,extreme_y;

struct{
REALTYPE *data;
int size;
}curve;
private:
inline REALTYPE clamp1(REALTYPE m){
if (m<0.0) return 0.0;
if (m>1.0) return 1.0;
return m;
};
inline void swap(REALTYPE &m1,REALTYPE &m2){
REALTYPE tmp=m1;
m1=m2;
m2=tmp;
};
FreeEditPos *pos;
int npos;
REALTYPE smooth;
INTERP_MODE interp_mode;
bool enabled;
};

#endif


+ 595
- 0
FreeEditUI.fl View File

@@ -0,0 +1,595 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0110
header_name {.h}
code_name {.cxx}
decl {\#include <FL/Fl_File_Chooser.H>} {}

decl {\#include <FL/Fl_Box.H>} {public
}

decl {\#include <FL/Fl_Group.H>} {public
}

decl {\#include <FL/Fl_Box.H>} {public
}

decl {\#include <FL/fl_draw.H>} {public
}

decl {\#include <FL/Fl_Value_Input.H>} {public
}

decl {\#include <FL/fl_ask.H>} {public
}

decl {\#include<sys/stat.h>} {}

decl {\#include <stdio.h>} {}

decl {\#include <string>} {}

decl {\#include "Control.h"} {public
}

decl {\#include <math.h>} {}

decl {\#include "FreeEdit.h"} {public
}

decl {\#include <FL/Fl_Group.H>} {public
}

class FreeEditUI {open : {public Fl_Box}
} {
Function {FreeEditUI(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} {
code {max_value_fl=min_value_fl=value_fl=position_fl=NULL;
free_edit=NULL;
control=NULL;

current_point=-1;
selected_point=-1;

default_value=1.0;} {}
}
Function {~FreeEditUI()} {} {
code {} {}
}
Function {init(FreeEdit *free_edit_,Control *control_)} {open
} {
code {free_edit=free_edit_;
control=control_;
free_edit->update_curve();} {}
}
Function {init_value_io(Fl_Value_Input *value_fl_,Fl_Value_Input *position_fl_,Fl_Value_Input *min_value_fl_,Fl_Value_Input *max_value_fl_)} {} {
code {value_fl=value_fl_;
position_fl=position_fl_;
min_value_fl=min_value_fl_;
max_value_fl=max_value_fl_;

if (free_edit){
free_edit->extreme_y.set_min(min_value_fl->value());
free_edit->extreme_y.set_max(max_value_fl->value());
};} {}
}
Function {get_color(Fl_Color c)} {return_type Fl_Color
} {
code {if (free_edit->get_enabled()) return c;

return fl_color_average(c,fl_rgb_color(178,178,178),0.1);} {}
}
Function {draw()} {open
} {
code {int ox=x(),oy=y(),lx=w(),ly=h();

//fl_color(FL_WHITE);
fl_color(get_color(color()));
fl_rectf(ox,oy,lx,ly);

//fl_color(FL_GRAY);
fl_color(get_color(labelcolor()));
//draw grid
fl_line_style(FL_SOLID);
for (int ncoord=0;ncoord<2;ncoord++){
FreeEditExtremes *extreme=(ncoord==0)?&free_edit->extreme_x:&free_edit->extreme_y;
if (extreme->get_scale()==FE_LOG){//logarithmic scale
float p10=pow(10,floor(log10(extreme->get_min())));
int psteps=(int)(floor(log10(extreme->get_max()/extreme->get_min())))+1;
for (int k=1;k<=psteps;k++){
for (int i=1;i<10;i++){
if (i==1) fl_line_style(FL_SOLID);
else if(i==5) fl_line_style(FL_DASH);
else fl_line_style(FL_DOT);
float fpos=extreme->real_value_to_coord(p10*i);
if ((fpos>0.0)&&(fpos<1.0)){
if (ncoord==0){
int pos=(int)(fpos*lx);
fl_line(ox+pos,oy,ox+pos,oy+ly);
}else{
int pos=(int)(ly-1-fpos*ly);
fl_line(ox,oy+pos,ox+lx,oy+pos);
};
};
};
p10*=10.0;
};
}else{//linear scale
float diff=extreme->get_max()-extreme->get_min();
float stepsize=pow(10,floor(log10( fabs(diff))))*0.1;
if (stepsize>=1e-6){
int nsteps=(int)(fabs(diff)/stepsize)+1;
if (nsteps>25) {
nsteps/=5;
stepsize*=5.0;
};
float min=extreme->get_min();
float max=extreme->get_max();
float min1=(min<max)?min:max;
int kstep=(int)(floor(min1/stepsize));
min1=kstep*stepsize;
for (int i=0;i<nsteps;i++){
float fpos=extreme->real_value_to_coord(min1+i*stepsize);
int ks=(i+kstep)%10; if (ks<0) ks+=10;
if (ks==0) fl_line_style(FL_SOLID);
else if (ks==5) fl_line_style(FL_DASH);
else fl_line_style(FL_DOT);
if ((fpos>0.0)&&(fpos<1.0)){
if (ncoord==0){
int pos=(int)(fpos*lx);
fl_line(ox+pos,oy,ox+pos,oy+ly);
}else{
int pos=(int)(ly-1-fpos*ly);
fl_line(ox,oy+pos,ox+lx,oy+pos);
};
};
};
};
};
};



//draw the line
fl_line_style(FL_SOLID,2);
fl_color(get_color(labelcolor()));
float *data=new float[lx];


free_edit->get_curve(lx,data,false);
int oldy=0;
for (int i=0;i<lx;i++){
int newy=(int)((1.0-data[i])*ly);
if (i) fl_line(ox+i-1,oy+oldy,ox+i,oy+newy);
oldy=newy;
};

delete[]data;

//draw points
fl_line_style(FL_SOLID,3);
for (int i=0;i<free_edit->get_npoints();i++){
if (!free_edit->is_enabled(i)) continue;
fl_color(FL_BLACK);
int x=(int)(free_edit->get_posx(i)*lx);
int y=(int)((1.0-free_edit->get_posy(i))*ly);
fl_circle(ox+x,oy+y,3);
if (i==selected_point){
fl_color(get_color(FL_RED));
fl_circle(ox+x,oy+y,4);
fl_circle(ox+x,oy+y,5);
};
};


/*
//test
{
fl_color(FL_RED);
fl_line_style(FL_SOLID);

free_edit->update_curve();

int oldy=0;
//printf("draw %g\\n",free_edit->get_value(8000.0));
//printf("d %g\\n",free_edit->curve.data[1000]);

for (int i=0;i<lx;i++){
//int m=(int)(((float)i/(float)lx)*(free_edit->curve.size-1));
//REALTYPE y=free_edit->curve.data[m];
REALTYPE freq=i/(float)lx*25000.0;
REALTYPE y=free_edit->get_value(freq);
//if (i<20) printf("%d %g\\n",i,y);
//printf("%g %g\\n",freq,y);


int newy=(int)((1.0-y)*ly);

if (i) fl_line(ox+i-1,oy+oldy,ox+i,oy+newy);
oldy=newy;
};
};
*/




/*


fl_color(FL_RED);
fl_line_style(FL_SOLID);


int samplerate=44100;

int nfreq=lx;
float *freq1=new float [nfreq];
float *freq2=new float [nfreq];
float *tmpfreq1=new float [nfreq*2];

for (int i=0;i<nfreq;i++) tmpfreq1[i]=0.0;

for (int i=0;i<nfreq;i++) freq1[i]=data[i];

//convert to log spectrum
float minfreq=20.0;
float maxfreq=0.5*samplerate;
for (int i=0;i<nfreq;i++){
float freqx=i/(float) nfreq;
float x=exp(log(minfreq)+freqx*(log(maxfreq)-log(minfreq)))/maxfreq*nfreq;
float y=0.0;
int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
float xp=x-x0;
if (x<nfreq){
y=freq1[x0]*(1.0-xp)+freq1[x1]*xp;
};
tmpfreq1[i]=y;
};
//increase bandwidth of each harmonic
int n=2;
float bandwidth=free_edit->get_posy(0);
float a=1.0-exp(-bandwidth*bandwidth*nfreq*0.002);
a=pow(a,n);
printf("%g\\n",a);

for (int k=0;k<n;k++){
tmpfreq1[0]=0.0;
for (int i=1;i<nfreq;i++){
tmpfreq1[i]=tmpfreq1[i-1]*a+tmpfreq1[i]*(1.0-a);
};
tmpfreq1[nfreq-1]=0.0;
for (int i=nfreq-2;i>0;i--){
tmpfreq1[i]=tmpfreq1[i+1]*a+tmpfreq1[i]*(1.0-a);
};
};

//convert back to linear spectrum
// for (int i=0;i<nfreq;i++) freq2[i]=0.0;
// for (int i=0;i<nfreq;i++) freq2[i]=tmpfreq1[i];

freq2[0]=0;
for (int i=1;i<nfreq;i++){
float freqx=i/(float) nfreq;
float x=log((freqx*maxfreq)/minfreq)/log(maxfreq/minfreq)*nfreq;
// printf("%g\\n",x);
float y=0.0;
int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
float xp=x-x0;
if (x<nfreq){
y=tmpfreq1[x0]*(1.0-xp)+tmpfreq1[x1]*xp;
};
freq2[i]=y;
};



for (int i=0;i<lx;i++){
REALTYPE y=freq2[i];

int newy=(int)((1.0-y)*ly);


if (i) fl_line(ox+i-1,oy+oldy,ox+i,oy+newy);
oldy=newy;
};
delete [] freq1;
delete [] freq2;
delete [] tmpfreq1;
// delete [] tmpfreq2;
*/} {}
}
Function {handle(int event)} {return_type int
} {
code {if (!free_edit->get_enabled()) return Fl_Box::handle(event);

int ox=x(),oy=y(),lx=w(),ly=h();
float px=(Fl::event_x()-ox)/(float)lx;
float py=1.0-(Fl::event_y()-oy)/(float)ly;
if (px<0) px=0;
else if (px>1.0) px=1.0;
if (py<0) py=0;
else if (py>1.0) py=1.0;

int closest=-1;
float xyrap=(float)ly/(float)lx;
for (int i=0;i<free_edit->get_npoints();i++){
if (!free_edit->is_enabled(i)) continue;
float d=pow(px-free_edit->get_posx(i),2)+pow(py-free_edit->get_posy(i),2)*xyrap;
if (d<0.0005) {
closest=i;
break;
};
};


if (event==FL_PUSH){
if (closest>=0) {
if (Fl::event_button()==1) selected_point=current_point=closest;
if ((Fl::event_button()==3)&&(closest>=2)) {
free_edit->set_enabled(closest,false);
current_point=selected_point=-1;
};
}else{
for (int i=0;i<free_edit->get_npoints();i++){
if (!free_edit->is_enabled(i)){
selected_point=closest=current_point=i;
free_edit->set_posx(current_point,px);
free_edit->set_posy(current_point,py);
free_edit->set_enabled(i,true);
break;
};
};
};
refresh_value();
redraw();
update_curve();
return true;
};
if (event==FL_RELEASE){
current_point=-1;
refresh_value();
update_curve();
if (control) control->update_process_parameters();
return true;
};

if (event==FL_DRAG){
if (current_point>=0){
if (current_point>=2) free_edit->set_posx(current_point,px);
free_edit->set_posy(current_point,py);
redraw();
};
refresh_value();
update_curve();
return true;
};

return Fl_Box::handle(event);} {}
}
Function {refresh_value()} {} {
code {if (!value_fl) return;
value_fl->deactivate();
position_fl->deactivate();
if (selected_point<0) return;
if (!free_edit->is_enabled(selected_point)) return;
value_fl->activate();
position_fl->activate();

float val=free_edit->extreme_y.coord_to_real_value(free_edit->get_posy(selected_point));
val=((int)(val*10000.0))/10000.0;
value_fl->value(val);


float pos=free_edit->extreme_x.coord_to_real_value(free_edit->get_posx(selected_point));
pos=((int)(pos*1000.0))/1000.0;
position_fl->value(pos);} {}
}
Function {set_selected_value(float val)} {} {
code {if (!value_fl) return;
if (selected_point<0) return;
if (!free_edit->is_enabled(selected_point)) return;

free_edit->set_posy(selected_point,free_edit->extreme_y.real_value_to_coord(val));
redraw();
update_curve();} {}
}
Function {set_selected_position(float pos)} {} {
code {if (!value_fl) return;
if (selected_point<0) return;
if (!free_edit->is_enabled(selected_point)) return;

free_edit->set_posx(selected_point,free_edit->extreme_x.real_value_to_coord(pos));
redraw();
update_curve();} {}
}
Function {set_min_value(float val)} {open
} {
code {unselect();

free_edit->extreme_y.set_min(val);
redraw();
update_curve();} {}
}
Function {set_max_value(float val)} {open
} {
code {unselect();

free_edit->extreme_y.set_max(val);
redraw();
update_curve();} {}
}
Function {unselect()} {} {
code {selected_point=-1;
refresh_value();
redraw();} {}
}
Function {set_smooth(float smooth)} {} {
code {free_edit->set_smooth(smooth);
redraw();
update_curve();} {}
}
Function {set_interp_mode(int interp_mode)} {} {
code {free_edit->set_interp_mode((FreeEdit::INTERP_MODE)interp_mode);
redraw();
update_curve();} {}
}
Function {clear()} {} {
code {for (int i=2;i<free_edit->get_npoints();i++) free_edit->set_enabled(i,false);
free_edit->set_all_values(default_value);
redraw();
update_curve();} {}
}
Function {update_curve()} {} {
code {free_edit->update_curve();} {}
}
decl {int current_point,selected_point;} {public
}
decl {Fl_Value_Input *value_fl,*position_fl,*min_value_fl,*max_value_fl;} {public
}
decl {FreeEdit *free_edit;} {public
}
decl {float default_value;} {public
}
decl {Control *control;} {public
}
}

class FreeEditControls {open : {public Fl_Group}
} {
Function {FreeEditControls(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} {
code {free_edit_ui=NULL;} {}
}
Function {~FreeEditControls()} {} {
code {hide();} {}
}
Function {init(FreeEditUI *free_edit_ui_,FREE_EDIT_EXTREME_SCALE scale_x=FE_LINEAR,float min_x=0.0,float max_x=1.0,FREE_EDIT_EXTREME_SCALE scale_val=FE_LINEAR,float min_val=0.0,float max_val=1.0,float default_value=1.0)} {open
} {
code {free_edit_ui=free_edit_ui_;

make_window();
end();

free_edit_ui->init_value_io(free_edit_value_fl,free_edit_position_fl,free_edit_min_value_fl,free_edit_max_value_fl);
feui->resize(this->x(),this->y(),this->w(),this->h());

FreeEdit *fe=free_edit_ui->free_edit;

fe->extreme_x.set_min(min_x);
fe->extreme_x.set_max(max_x);
fe->extreme_x.set_scale(scale_x);

fe->extreme_y.set_min(min_val);
fe->extreme_y.set_max(max_val);
fe->extreme_y.set_scale(scale_val);

free_edit_min_value_fl->value(min_val);
free_edit_max_value_fl->value(max_val);
free_edit_ui->default_value=default_value;
fe->set_all_values(default_value);

enabled_check->value(fe->get_enabled());} {}
}
Function {update_parameters()} {open
} {
code {if (free_edit_ui->control) free_edit_ui->control->update_process_parameters();} {}
}
Function {make_window()} {open
} {
Fl_Window feui {open
xywh {245 395 85 210} type Double color 50 labelfont 1
class Fl_Group visible
} {
Fl_Group {} {open
xywh {0 0 85 210} box PLASTIC_THIN_UP_BOX color 52 labeltype ENGRAVED_LABEL labelsize 10 align 0
} {
Fl_Value_Input free_edit_min_value_fl {
label {Val.Min}
callback {free_edit_ui->unselect();
free_edit_ui->set_min_value(o->value());
update_parameters();}
xywh {5 110 50 15} labelsize 10 align 5 minimum -10000 maximum 10000 textfont 1 textsize 10
}
Fl_Value_Input free_edit_max_value_fl {
label {Val.Max}
callback {free_edit_ui->unselect();
free_edit_ui->set_max_value(o->value());
update_parameters();}
xywh {5 140 50 15} labelsize 10 align 5 minimum -10000 maximum 10000 value 1 textfont 1 textsize 10
}
Fl_Value_Input free_edit_value_fl {
label Value
callback {free_edit_ui->set_selected_value(o->value());
update_parameters();}
xywh {5 75 70 15} labelfont 1 labelsize 10 align 5 minimum 0.03 maximum 100 value 0.5 textfont 1 textsize 10 deactivate
}
Fl_Roller free_edit_smooth {
label Sm
callback {free_edit_ui->set_smooth(o->value());
update_parameters();}
tooltip {Smooth function} xywh {60 110 15 45} labelsize 10 align 1 when 4 minimum 1 maximum 0 step 0.01
}
Fl_Choice free_edit_interpolate {
label Interpolate
callback {free_edit_ui->set_interp_mode(o->value());
update_parameters();}
xywh {5 170 70 15} down_box BORDER_BOX labelsize 11 align 5 textfont 1 textsize 10
} {
MenuItem {} {
label Linear
xywh {10 10 36 21} labelfont 1 labelsize 10
}
MenuItem {} {
label Cosine
xywh {10 10 36 21} labelfont 1 labelsize 10
}
}
Fl_Button {} {
label clear
callback {if (!fl_choice("Delete all points?","No","Yes",NULL)) return;
free_edit_ui->clear();
update_parameters();}
xywh {5 190 75 15} labelsize 12
}
Fl_Light_Button enabled_check {
label Enable
callback {free_edit_ui->free_edit->set_enabled(o->value());
free_edit_ui->update_curve();
free_edit_ui->redraw();
update_parameters();}
xywh {5 5 75 20} color 7 selection_color 88 labelfont 1
}
Fl_Value_Input free_edit_position_fl {
label Position
callback {free_edit_ui->set_selected_position(o->value());
update_parameters();}
xywh {5 45 70 15} labelsize 10 align 5 minimum 0.0001 maximum 10000 value 1 textfont 1 textsize 10 deactivate
}
}
}
}
Function {refresh()} {open
} {
code {enabled_check->value(free_edit_ui->free_edit->get_enabled());

free_edit_min_value_fl->value(free_edit_ui->free_edit->extreme_y.get_min());
free_edit_max_value_fl->value(free_edit_ui->free_edit->extreme_y.get_max());
free_edit_interpolate->value(free_edit_ui->free_edit->get_interp_mode());
free_edit_smooth->value(free_edit_ui->free_edit->get_smooth());

free_edit_ui->update_curve();
free_edit_ui->redraw();
update_parameters();} {selected
}
}
decl {FreeEditUI *free_edit_ui;} {}
}

+ 933
- 0
GUI.fl View File

@@ -0,0 +1,933 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0110
header_name {.h}
code_name {.cxx}
decl {//Copyright (c) Nasca Octavian Paul. Released under GNU General Public License version 2} {public
}

decl {\#include <FL/Fl_File_Chooser.H>} {}

decl {\#include <FL/Fl_Box.H>} {public
}

decl {\#include <FL/Fl_Group.H>} {public
}

decl {\#include <FL/Fl_Box.H>} {public
}

decl {\#include <FL/fl_draw.H>} {public
}

decl {\#include <FL/Fl_Value_Input.H>} {public
}

decl {\#include <FL/fl_ask.H>} {public
}

decl {\#include<sys/stat.h>} {}

decl {\#include <stdio.h>} {}

decl {\#include <string>} {}

decl {\#include <math.h>} {}

decl {\#include "Control.h"} {public
}

decl {\#include "FreeEditUI.h"} {public
}

decl {\#include "version.h"} {public
}

Function {hex4n(char c)} {return_type int
} {
code {if (c>96) c-=32;
if ((c>='0')||(c<='9')) return (c-'0');
if ((c>='A')||(c<='F')) return (c-'A')+10;

return 0;} {}
}

Function {unescape(std::string s)} {return_type {std::string}
} {
code {std::string result;
int slen=s.size();
s+=" ";
int sk=0;
while (sk<slen){
char c=s[sk];
if (c=='%'){
char c1=s[++sk];
char c2=s[++sk];
result+=(char)(16*hex4n(c1)+hex4n(c2));
sk++;
}else{
result+=c;
sk++;
};
};


//printf("%s\\n%s\\n",s.c_str(),result.c_str());
return result;} {}
}

class DDBox {: {public Fl_Box}
} {
Function {DDBox(int x, int y, int w, int h, const char *label = 0):Fl_Box(x,y,w,h,label)} {open
} {
code {new_drag_file=false;} {}
}
Function {handle(int event)} {open return_type int
} {
code {if ((event==FL_DND_ENTER)||(event==FL_DND_DRAG)||(event==FL_DND_RELEASE)) return 1;
if (event==FL_PASTE){
const char *url=Fl::event_text();
if (strstr(url,"file://")!=url) return 0;//is not a file
std::string filename=url+7;
for (int i=0;i<filename.size();i++) if (filename[i]<32) filename[i]=0;
drag_file=unescape(filename);
new_drag_file=true;
return 1;
};
return Fl_Box::handle(event);} {}
}
decl {std::string drag_file;} {public
}
decl {bool new_drag_file;} {public
}
}

class GUI {open
} {
decl {enum Mode {STOP,PLAY,PAUSE,FREEZE};} {}
Function {GUI()} {} {
code {playing_for_button=false;
eof_for_button=false;
rendering=false;
make_window();
tick(this);
refresh();
set_mode(STOP);} {}
}
Function {~GUI()} {} {
code {Fl::remove_timeout(tick,this);} {}
}
Function {open_input_file(const char *filename)} {open
} {
code {const char *ext=fl_filename_ext(filename);
FILE_TYPE intype=FILE_WAV;
if ((strcmp(ext,".ogg")==0)||(strcmp(ext,".OGG")==0)||(strcmp(ext,".Ogg")==0)) intype=FILE_VORBIS;
if ((strcmp(ext,".mp3")==0)||(strcmp(ext,".MP3")==0)||(strcmp(ext,".Mp3")==0)) intype=FILE_MP3;
bool result=control.set_input_filename(filename,intype);
if (result) {
infilename_output->copy_label(control.get_input_filename_and_info().c_str());
} else {
infilename_output->copy_label("");
fl_alert("Error: Could not open audio file:\\n%s",filename);
};
refresh();} {}
}
Function {render()} {open
} {
code {render_button->deactivate();
rendering=true;
render_percent_slider->value(0);
render_percent_slider->activate();
cancel_render_button->activate();
//char defaultfile[FL_PATH_MAX];
//fl_filename_absolute(defaultfile,control.get_recommanded_output_filename().c_str());
Fl_File_Chooser *fc=new Fl_File_Chooser(NULL,"Wave files (*.wav)\\tOgg Vorbis (*.ogg)",Fl_File_Chooser::CREATE,"Render to audio file...");

fc->preview(0);
fc->filter_value(0);
fc->ok_label("Render");
fc->show();
while (fc->visible()){
Fl::wait();
};

const char *newfile = fc->value();
if (newfile != NULL) {
if (file_exists(newfile)){
if (!fl_choice("The file exists. \\nOverwrite it?","No","Yes",NULL)) return;
};

FILE_TYPE type=FILE_WAV;
if (fc->filter_value()==1) type=FILE_VORBIS;
const char *ext=fl_filename_ext(newfile);
std::string outfilename=newfile;
if (strlen(ext)==0){
if (type==FILE_VORBIS) outfilename+=".ogg";
else outfilename+=".wav";
};
render_percent_slider->copy_label(outfilename.c_str());
FILE_TYPE intype=FILE_WAV;
{
const char *ext=fl_filename_ext(control.get_input_filename().c_str());
if ((strcmp(ext,".ogg")==0)||(strcmp(ext,".OGG")==0)||(strcmp(ext,".Ogg")==0)) intype=FILE_VORBIS;
if ((strcmp(ext,".MP3")==0)||(strcmp(ext,".mp3")==0)||(strcmp(ext,".Mp3")==0)) intype=FILE_MP3;
};
const char *outstr=control.Render(control.get_input_filename(),outfilename,type,intype,
selection_pos1->value()/100.0,selection_pos2->value()/100.0).c_str();
if (strlen(outstr)!=0) fl_alert("%s",outstr);
};

delete fc;
render_button->activate();
render_percent_slider->value(0);
render_percent_slider->deactivate();
render_percent_slider->label("");
cancel_render_button->deactivate();
rendering=false;} {}
}
Function {make_window()} {open private
} {
Fl_Window window {
label {Paul's Extreme Sound Stretch} open
xywh {54 265 995 550} type Double resizable
code0 {if(strlen(VERSION)<2) {o->color(FL_BLUE); o->label("VERSION NOT SET!!!!!!!!!!!!");};} visible
} {
Fl_Menu_Bar {} {open
xywh {0 0 1015 20}
} {
Submenu {} {
label File open
xywh {0 0 63 20}
} {
MenuItem {} {
label {Open audio file...}
callback {char *newfile = fl_file_chooser("Open Audio(ogg,wav,mp3) File?", NULL, NULL);
if (newfile != NULL) {
open_input_file(newfile);
};
selection_pos1->value(0.0);
selection_pos2->value(100.0);

refresh();}
xywh {0 0 30 20}
}
MenuItem render_menu {
label {Render and save audio file...}
callback {selection_pos1->value(0.0);
selection_pos2->value(100.0);
tabs_widget->value(write_to_file_group);
render();}
xywh {10 10 30 20} deactivate divider
}
MenuItem {} {
label {Open Parameters...}
callback {char *newfile = fl_file_chooser("Open Parameter File?", "PaulStretch XML (*.psx)\\tAll Files (*)", NULL);
if (newfile != NULL) {
set_mode(STOP);
control.stopplay();
if (!control.load_parameters(newfile)){
fl_alert("Error: Could not load parameter file:\\n%s",newfile);
};
};
refreshgui();
refresh();}
xywh {10 10 30 20}
}
MenuItem {} {
label {Save Parameters...}
callback {char *newfile = fl_file_chooser("Save Parameters(paulstretch) File?", "PaulStretch XML (*.psx)\\tAll Files (*)", NULL);
if (newfile != NULL) {
if (file_exists(newfile)){
if (!fl_choice("The file exists. \\nOverwrite it?","No","Yes",NULL)) return;
};
control.save_parameters(newfile);
};
refresh();}
xywh {20 20 30 20} divider
}
MenuItem {} {
label Exit
callback {window->hide();}
xywh {0 0 30 20}
}
}
Submenu {} {
label About
xywh {15 15 63 20}
} {
MenuItem {} {
label {About...}
callback {aboutwindow->show();}
xywh {15 15 30 20}
}
}
}
Fl_Tabs tabs_widget {open
xywh {5 50 985 420} box BORDER_BOX
} {
Fl_Group {} {
label Parameters open selected
xywh {5 70 985 400}
} {
Fl_Slider stretch_slider {
label {Stretch:}
callback {refresh();
control.update_player_stretch();}
xywh {10 89 975 15} type {Horz Knob} box FLAT_BOX align 6 value 0.29
}
Fl_Slider fftsize_slider {
label {Window Size:}
callback {refresh();
o->labelcolor(FL_BLUE);}
xywh {10 155 975 15} type {Horz Knob} box FLAT_BOX align 6 value 0.47
}
Fl_Choice mode_choice {
label {Mode:}
callback {refresh();}
xywh {850 110 135 20} down_box BORDER_BOX
} {
MenuItem {} {
label Stretch
xywh {10 10 30 20}
}
MenuItem {} {
label HyperStretch
xywh {20 20 30 20}
}
MenuItem {} {
label Shorten
xywh {0 0 30 20}
}
}
Fl_Choice window_choice {
label {Type:}
callback {FFTWindow w=W_RECTANGULAR;
switch(o->value()){
case 0:
w=W_RECTANGULAR;
break;
case 1:
w=W_HAMMING;
break;
case 2:
w=W_HANN;
break;
case 3:
w=W_BLACKMAN;
break;
case 4:
w=W_BLACKMAN_HARRIS;
break;
};

control.set_window_type(w);
refresh();}
xywh {850 185 135 20} down_box BORDER_BOX when 1
code0 {o->value(2);}
} {
MenuItem {} {
label Rectangular
xywh {40 40 30 20}
}
MenuItem {} {
label Hamming
xywh {30 30 30 20}
}
MenuItem {} {
label Hann
xywh {10 10 30 20}
}
MenuItem {} {
label Blackman
xywh {20 20 30 20}
}
MenuItem {} {
label BlackmanHarris
xywh {30 30 30 20}
}
}
Fl_Button {} {
label S
callback {char tmp[100];
snprintf(tmp,100,"%g",control.get_stretch());
const char *result=fl_input("Enter the stretch value",tmp);
if (!result) return;

double str=atof(result);
if (str<1e-4) return;

double stc=control.get_stretch_control(str,mode_choice->value());

if ((stc<1e-4)||(stc>1.0)) return;
stretch_slider->value(stc);
stretch_slider->do_callback();}
tooltip {set the stretch to a value} xywh {780 110 20 20}
}
Fl_Box resolution_box {
xywh {10 187 790 18} box FLAT_BOX color 52 align 20
}
Fl_Group {} {
label {Stretch Multiplier} open
xywh {10 245 975 220} box THIN_UP_BOX labeltype ENGRAVED_LABEL
} {
Fl_Box stretch_free_edit {
label Graph
xywh {105 250 875 210} box FLAT_BOX color 17
code0 {o->init(&control.ppar.stretch_multiplier,&control);}
class FreeEditUI
}
Fl_Group stretch_multiplier_control {open
xywh {15 250 85 210} box BORDER_FRAME color 0 align 208
code0 {o->init(stretch_free_edit,FE_LINEAR,0,100.0,FE_LOG,0.1,50.0,1.0);}
class FreeEditControls
} {}
}
}
Fl_Group {} {
label Process
xywh {5 70 985 400} hide
} {
Fl_Group {} {open
xywh {165 75 105 65} box BORDER_BOX
} {
Fl_Check_Button pitch_shift_enabled {
label {Pitch Shift}
callback {control.ppar.pitch_shift.enabled=o->value();
control.update_process_parameters();}
xywh {170 80 90 15} down_box DOWN_BOX labelfont 1
}
Fl_Counter pitch_shift_cents {
label cents
callback {control.ppar.pitch_shift.cents=(int)o->value();
control.update_process_parameters();}
xywh {170 100 90 20} minimum -3600 maximum 3600 step 1
code0 {o->lstep(100);}
}
}
Fl_Group {} {open
xywh {275 75 135 100} box BORDER_BOX
} {
Fl_Check_Button octave_enabled {
label {Octave Mixer}
callback {control.ppar.octave.enabled=o->value();
control.update_process_parameters();}
xywh {280 80 110 15} down_box DOWN_BOX labelfont 1
}
Fl_Slider octave_om2 {
label {-2}
callback {control.ppar.octave.om2=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {2 octaves below} xywh {280 100 15 55} type {Vert Knob} minimum 1 maximum 0
}
Fl_Slider octave_om1 {
label {-1}
callback {control.ppar.octave.om1=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {1 octave below} xywh {300 100 15 55} type {Vert Knob} minimum 1 maximum 0
}
Fl_Slider octave_o0 {
label 0
callback {control.ppar.octave.o0=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {original (dry)} xywh {320 100 15 55} type {Vert Knob} minimum 1 maximum 0 value 1
}
Fl_Slider octave_o1 {
label 1
callback {control.ppar.octave.o1=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {1 octave above} xywh {340 100 15 55} type {Vert Knob} minimum 1 maximum 0
}
Fl_Slider octave_o15 {
label {1.5}
callback {control.ppar.octave.o15=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {3rd harmonic} xywh {360 100 15 55} type {Vert Knob} minimum 1 maximum 0
}
Fl_Slider octave_o2 {
label 2
callback {control.ppar.octave.o2=pow(o->value(),2.0);
control.update_process_parameters();}
tooltip {2 octaves above} xywh {380 100 15 55} type {Vert Knob} minimum 1 maximum 0
}
}
Fl_Group {} {open
xywh {165 140 105 65} box BORDER_BOX
} {
Fl_Check_Button freq_shift_enabled {
label {Freq Shift}
callback {control.ppar.freq_shift.enabled=o->value();
control.update_process_parameters();}
xywh {170 145 90 15} down_box DOWN_BOX labelfont 1
}
Fl_Counter freq_shift_Hz {
label Hz
callback {control.ppar.freq_shift.Hz=(int)o->value();
control.update_process_parameters();}
xywh {170 165 90 20} minimum -10000 maximum 10000 step 1
code0 {o->lstep(100);}
}
}
Fl_Group {} {open
xywh {605 75 120 65} box BORDER_BOX
} {
Fl_Check_Button compressor_enabled {
label Compress
callback {control.ppar.compressor.enabled=o->value();
control.update_process_parameters();}
xywh {610 80 90 15} down_box DOWN_BOX labelfont 1
}
Fl_Slider compressor_power {
label Power
callback {control.ppar.compressor.power=o->value();
control.update_process_parameters();}
xywh {610 100 110 15} type {Horz Knob}
}
}
Fl_Slider {} {
label Volume
callback {REALTYPE x=o->value();
x=pow(10.0,pow(x,1.5)-1.0)-0.1;
control.set_volume(x);}
xywh {605 155 120 40} type {Horz Knob} labelfont 1 minimum 0.3 maximum 1.6 value 1
}
Fl_Group {} {open
xywh {415 75 185 100} box BORDER_BOX
} {
Fl_Check_Button filter_enabled {
label Filter
callback {control.ppar.filter.enabled=o->value();
control.update_process_parameters();}
xywh {420 80 70 15} down_box DOWN_BOX labelfont 1
}
Fl_Value_Input filter_low {
label {Freq1(Hz)}
callback {control.ppar.filter.low=o->value();
control.update_process_parameters();}
xywh {420 101 100 24} align 8 maximum 10000
}
Fl_Value_Input filter_high {
label {Freq2(Hz)}
callback {control.ppar.filter.high=o->value();
control.update_process_parameters();}
xywh {420 126 100 24} align 8 maximum 25000 value 22000
}
Fl_Check_Button filter_stop {
label BandStop
callback {control.ppar.filter.stop=o->value();
control.update_process_parameters();}
tooltip {band-stop filter} xywh {500 80 90 15} down_box DOWN_BOX
}
Fl_Slider filter_hdamp {
label DHF
callback {control.ppar.filter.hdamp=o->value();
control.update_process_parameters();}
tooltip {Damp High Frequency} xywh {420 155 140 15} type {Horz Knob} align 8
}
}
Fl_Group {} {open
xywh {10 75 150 120} box BORDER_BOX
} {
Fl_Check_Button harmonics_enabled {
label Harmonics
callback {control.ppar.harmonics.enabled=o->value();
control.update_process_parameters();}
xywh {15 80 95 15} down_box DOWN_BOX labelfont 1
}
Fl_Value_Input harmonics_freq {
label {F.Freq(Hz)}
callback {control.ppar.harmonics.freq=o->value();
control.update_process_parameters();}
tooltip {fundamental frequency} xywh {15 101 65 24} align 8 minimum 1 maximum 20000 value 440
}
Fl_Value_Input harmonics_bandwidth {
label {BW(cents)}
callback {control.ppar.harmonics.bandwidth=o->value();
control.update_process_parameters();}
tooltip {bandwidth (cents)} xywh {15 126 65 24} align 8 minimum 0.1 maximum 200 value 25
}
Fl_Check_Button harmonics_gauss {
label Gauss
callback {control.ppar.harmonics.gauss=o->value();
control.update_process_parameters();}
tooltip {smooth the harmonics} xywh {85 155 65 15} down_box DOWN_BOX
}
Fl_Counter harmonics_nharmonics {
label {no.hrm.}
callback {control.ppar.harmonics.nharmonics=(int)o->value();
control.update_process_parameters();}
tooltip {number of harmonics} xywh {15 155 56 20} type Simple minimum 1 maximum 100 step 1 value 10
}
}
Fl_Group {} {open
xywh {275 180 325 40} box BORDER_BOX
} {
Fl_Check_Button spread_enabled {
label Spread
callback {control.ppar.spread.enabled=o->value();
control.update_process_parameters();}
xywh {280 185 90 15} down_box DOWN_BOX labelfont 1
}
Fl_Slider spread_bandwidth {
label Bandwidth
callback {control.ppar.spread.bandwidth=o->value();
control.update_process_parameters();}
xywh {360 185 230 15} type {Horz Knob} value 0.3
}
}
Fl_Group {} {
label ArbitraryFilter
xywh {10 245 975 220} box THIN_UP_BOX labeltype ENGRAVED_LABEL
} {
Fl_Box filter_free_edit {
label Graph
xywh {105 250 875 210} box FLAT_BOX color 206 selection_color 0
code0 {o->init(&control.ppar.free_filter,&control);}
class FreeEditUI
}
Fl_Group arbitrary_filter_control {open
xywh {15 250 85 210} box BORDER_FRAME color 0 align 208
code0 {o->init(filter_free_edit,FE_LOG,20.0,25000.0,FE_DB,-60,20,0.0);}
class FreeEditControls
} {}
}
}
Fl_Group {} {
label {Binaural beats}
xywh {5 70 985 400} box THIN_UP_BOX hide
} {
Fl_Box binaural_free_edit {
label Graph
xywh {135 75 845 390} box FLAT_BOX color 135
code0 {o->init(&control.bbpar.free_edit,&control);}
class FreeEditUI
}
Fl_Slider bbpar_mono {
label Pow
callback {control.bbpar.mono=o->value();
control.update_process_parameters();}
xywh {105 75 20 190} type {Vert Knob} labelfont 1 minimum 1 maximum 0 value 0.5
}
Fl_Group binaural_beats_control {
label {FreeEdit Controls}
xywh {10 75 80 205} box BORDER_FRAME color 47 align 208
code0 {o->init(binaural_free_edit,FE_LINEAR,0,100.0,FE_LOG,0.1,50.0,8.0);}
class FreeEditControls
} {}
Fl_Choice bbpar_stereo_mode {
label {Stereo Mode}
callback {control.bbpar.stereo_mode=(BB_STEREO_MODE)o->value();
control.update_process_parameters();}
xywh {10 305 110 20} down_box BORDER_BOX align 5
} {
MenuItem {} {
label LeftRight
xywh {10 10 36 21} labelfont 1
}
MenuItem {} {
label RightLeft
xywh {20 20 36 21} labelfont 1
}
MenuItem {} {
label Symmetric
xywh {30 30 36 21} labelfont 1
}
}
}
Fl_Group write_to_file_group {
label {Write to file} open
xywh {5 70 985 400} hide
} {
Fl_Button render_button {
label {Render selection...}
callback {render();}
xywh {250 95 320 30} labelfont 1 labelsize 22
}
Fl_Value_Slider render_percent_slider {
label { }
xywh {15 245 970 65} type {Horz Fill} selection_color 4 align 70 maximum 100 step 0.1 textsize 14
}
Fl_Button cancel_render_button {
label Cancel
callback {if (fl_choice("Cancel audio rendering?","No","Yes",NULL)) control.info.cancel_render=true;}
xywh {400 365 145 25} deactivate
}
Fl_Button {} {
label {selection pos1}
callback {selection_pos1->value(seek_slider->value());}
tooltip {set selection start from Player's position} xywh {20 85 110 20} align 20
}
Fl_Button {} {
label {selection pos2}
callback {selection_pos2->value(seek_slider->value());}
tooltip {set selection end from Player's position} xywh {20 110 110 20} align 20
}
Fl_Button {} {
label {select all}
callback {selection_pos1->value(0.0);
selection_pos2->value(100.0);}
tooltip {select the whole sound} xywh {20 135 110 20}
}
Fl_Value_Output selection_pos1 {
label {%}
xywh {135 85 70 20} align 72 maximum 100 step 0.01 textfont 1
}
Fl_Value_Output selection_pos2 {
label {%}
xywh {135 111 70 18} align 72 maximum 100 step 0.01 value 100 textfont 1
}
Fl_Check_Button {} {
label 32bit
callback {control.wav32bit=o->value();}
xywh {250 135 100 15} down_box DOWN_BOX
}
}
}
Fl_Box infilename_output {
tooltip {drag audio file here to open it} xywh {5 24 1005 22} box FLAT_BOX color 17 align 84
class DDBox
}
Fl_Group {} {
xywh {5 475 985 70} box BORDER_BOX
} {
Fl_Group {} {open
xywh {10 490 190 40} box THIN_UP_BOX color 16
} {
Fl_Button play_button {
label {@>}
callback {if (control.playing_eof()&&(seek_slider->value()>99.0)){
seek_slider->value(0.0);
seek_slider->do_callback();
};
set_mode(PLAY);
playing_for_button=true;
eof_for_button=true;

bool bypass=false;
if (Fl::event_button()==FL_RIGHT_MOUSE) bypass=true;

control.startplay(bypass);}
tooltip Play xywh {20 500 40 20} box PLASTIC_UP_BOX
}
Fl_Button freeze_button {
label {@<-> F}
callback {control.freezeplay();
set_mode(FREEZE);}
tooltip Freeze xywh {65 500 40 20} box PLASTIC_UP_BOX
}
Fl_Button {} {
label {@||}
callback {set_mode(PAUSE);
control.pauseplay();}
tooltip Pause xywh {110 500 40 20} box PLASTIC_UP_BOX
}
Fl_Button {} {
label {@square}
callback {set_mode(STOP);
control.stopplay();}
tooltip Stop xywh {155 500 40 20} box PLASTIC_UP_BOX
}
}
Fl_Value_Slider seek_slider {
label Percents
callback {control.set_seek_pos(o->value()/o->maximum());}
xywh {205 490 780 20} type {Horz Knob} box THIN_UP_BOX color 16 selection_color 4 align 6 maximum 100 textsize 14
}
}
}
Fl_Window aboutwindow {
label {About...}
xywh {274 354 300 170} type Double color 7 hide modal
} {
Fl_Button {} {
label OK
callback {aboutwindow->hide();}
xywh {110 140 64 20}
}
Fl_Box {} {
label {Copyright (c) 2006-2011 Nasca Octavian PAUL, Tg. Mures, Romania}
xywh {10 93 280 37} align 128
}
Fl_Box {} {
label {This is a software for extreme time stretching of the audio.}
xywh {5 53 290 32} align 128
}
Fl_Box {} {
label {Paul's Extreme Sound Stretch}
xywh {20 6 255 21} labelfont 1 align 128
}
Fl_Box {} {
label version
xywh {20 26 255 19} labelfont 1 align 128
code0 {o->label(VERSION);}
}
}
}
Function {set_mode(Mode mode)} {private
} {
code {switch (mode){
case STOP:
play_button->labelcolor(FL_BLACK);
mode_choice->activate();
freeze_button->deactivate();
break;

case PAUSE:
play_button->labelcolor(FL_BLACK);
mode_choice->activate();
break;
case PLAY:
play_button->labelcolor(FL_RED);
mode_choice->deactivate();
fftsize_slider->labelcolor(FL_BLACK);
freeze_button->activate();
break;
case FREEZE:
if (control.is_freeze()) freeze_button->labelcolor(FL_GREEN);
else freeze_button->labelcolor(FL_BLACK);
break;
};
window->redraw();} {}
}
Function {refresh()} {open
} {
code {double stretch_s=stretch_slider->value()/stretch_slider->maximum();

int mode=mode_choice->value();
double resolution_s=fftsize_slider->value()/fftsize_slider->maximum();

control.set_stretch_controls(stretch_s,mode,resolution_s);

stretch_slider->copy_label(control.get_stretch_info().c_str());
fftsize_slider->copy_label(control.get_fftsize_info().c_str());
resolution_box->copy_label(control.get_fftresolution_info().c_str());

bool may_render=false;
if (infilename_output->label()!=NULL){
if (strlen(infilename_output->label())!=0)
may_render=true;
};
if (!rendering){//do not change the status of render button while rendering
if (may_render) {
render_button->activate();
render_menu->activate();
} else {
render_button->deactivate();
render_menu->deactivate();
};
};} {}
}
Function {refreshgui()} {open
} {
code {stretch_slider->value(control.gui_sliders.stretch_s);
fftsize_slider->value(control.gui_sliders.fftsize_s);
mode_choice->value(control.gui_sliders.mode_s);
window_choice->value(control.window_type);



pitch_shift_enabled->value(control.ppar.pitch_shift.enabled);
pitch_shift_cents->value(control.ppar.pitch_shift.cents);

octave_enabled->value(control.ppar.octave.enabled);
octave_om2->value(control.ppar.octave.om2);
octave_om1->value(control.ppar.octave.om1);
octave_o0->value(control.ppar.octave.o0);
octave_o1->value(control.ppar.octave.o1);
octave_o15->value(control.ppar.octave.o15);
octave_o2->value(control.ppar.octave.o2);

freq_shift_enabled->value(control.ppar.freq_shift.enabled);
freq_shift_Hz->value(control.ppar.freq_shift.Hz);

compressor_enabled->value(control.ppar.compressor.enabled);
compressor_power->value(control.ppar.compressor.power);

filter_enabled->value(control.ppar.filter.enabled);
filter_stop->value(control.ppar.filter.stop);
filter_low->value(control.ppar.filter.low);
filter_high->value(control.ppar.filter.high);
filter_hdamp->value(control.ppar.filter.hdamp);

harmonics_enabled->value(control.ppar.harmonics.enabled);
harmonics_freq->value(control.ppar.harmonics.freq);
harmonics_bandwidth->value(control.ppar.harmonics.bandwidth);
harmonics_nharmonics->value(control.ppar.harmonics.nharmonics);
harmonics_gauss->value(control.ppar.harmonics.gauss);

spread_enabled->value(control.ppar.spread.enabled);
spread_bandwidth->value(control.ppar.spread.bandwidth);


bbpar_mono->value(control.bbpar.mono);
bbpar_stereo_mode->value(control.bbpar.stereo_mode);


stretch_multiplier_control->refresh();
arbitrary_filter_control->refresh();
binaural_beats_control->refresh();} {}
}
Function {tickrefresh()} {} {
code {seek_slider->value(seek_slider->maximum()*control.get_seek_pos());

if (playing_for_button&&control.playing()){
play_button->labelcolor(FL_GREEN);
window->redraw();
playing_for_button=false;
};
if (eof_for_button&&control.playing_eof()){
play_button->labelcolor(FL_BLACK);
window->redraw();
eof_for_button=false;
};

if (control.info.render_percent>0.0){
render_percent_slider->value(control.info.render_percent);
};
if (infilename_output->new_drag_file){
open_input_file(infilename_output->drag_file.c_str());
infilename_output->new_drag_file=false;
};} {}
}
Function {tickdraw(GUI *o)} {return_type {static void}
} {
code {o->tickrefresh();} {}
}
Function {tick(void *v)} {return_type {static void}
} {
code {tickdraw((GUI *) v);
Fl::add_timeout(1.0/3.0,tick,v);//3 fps} {}
}
decl {Control control;} {}
decl {bool playing_for_button;} {}
decl {bool rendering;} {}
decl {bool eof_for_button;} {}
}

Function {file_exists(const char *filename)} {return_type bool
} {
code {struct stat buf;
int i = stat ( filename, &buf );
// File exists
if ( i == 0 ) return true;
else return false;} {}
}

Function {main(int argc, char *argv[])} {return_type int
} {
code {GUI *gui=new GUI();

if (argc>1){
gui->open_input_file(argv[1]);
};
gui->window->show();


Fl::run();

delete gui;

return 0;} {}
}

+ 90
- 0
Input/AInputS.cpp View File

@@ -0,0 +1,90 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


#include <stdio.h>
#include <stdlib.h>
#include "AInputS.h"
using namespace std;

AInputS::AInputS(){
handle=AF_NULL_FILEHANDLE;
info.nsamples=0;
info.nchannels=0;
info.samplerate=1;
info.currentsample=0;
eof=false;
};

AInputS::~AInputS(){
close();
};

bool AInputS::open(string filename){
close();//inchide un posibil fisier existent
handle=afOpenFile(filename.c_str(),"r",0);
if (handle==AF_NULL_FILEHANDLE){//eroare
eof=true;
return false;
};
afSetVirtualChannels(handle,AF_DEFAULT_TRACK,2);

eof=false;
info.nsamples=afGetFrameCount(handle,AF_DEFAULT_TRACK);
info.nchannels=afGetVirtualChannels(handle,AF_DEFAULT_TRACK);
info.samplerate=(int) afGetRate(handle,AF_DEFAULT_TRACK);
info.currentsample=0;
if (info.samplerate==0) return false;
//fac ca intrarea sa fie pe 16 biti
afSetVirtualSampleFormat(handle,AF_DEFAULT_TRACK,AF_SAMPFMT_TWOSCOMP,16);
return true;
};

void AInputS::close(){
if (handle!=AF_NULL_FILEHANDLE){
afCloseFile(handle);
handle=AF_NULL_FILEHANDLE;
};
};

int AInputS::read(int nsmps,short int *smps){
if (handle==AF_NULL_FILEHANDLE) return 0;

int readed=afReadFrames(handle,AF_DEFAULT_TRACK,smps,nsmps);
info.currentsample+=readed;
if (readed!=nsmps) {
info.currentsample=info.nsamples;
eof=true;
};
return readed;
};

void AInputS::seek(double pos){
if (handle==AF_NULL_FILEHANDLE) return;
AFframecount p=(AFframecount)(pos*info.nsamples);
if (p==info.currentsample) return;
AFframecount seek=afSeekFrame(handle,AF_DEFAULT_TRACK,p);
//
printf("AInputS::seek %d %d %d - possible audiofile bug (it always seeks to the end of the file) \n",(int)p,(int)seek,(int)afGetFrameCount(handle,AF_DEFAULT_TRACK));
info.currentsample=p;
};


+ 40
- 0
Input/AInputS.h View File

@@ -0,0 +1,40 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef AINPUT_H
#define AINPUT_H
#include <string>

#include <audiofile.h>
#include "InputS.h"

class AInputS:public InputS{
public:
AInputS();
~AInputS();
bool open(std::string filename);
void close();

int read(int nsmps,short int *smps);
void seek(double pos);//0=start,1.0=end
private:
AFfilehandle handle;
};
#endif

+ 43
- 0
Input/InputS.h View File

@@ -0,0 +1,43 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef INPUTS_H
#define INPUTS_H
#include "../globals.h"

class InputS{
public:
virtual bool open(std::string filename)=0;
virtual void close()=0;

virtual int read(int nsmps,short int *smps)=0;
virtual void seek(double pos)=0;//0=start,1.0=end

struct {
int nsamples;
int nchannels;
int samplerate;
int currentsample;
} info;
bool eof;
};

#endif



+ 209
- 0
Input/MP3InputS.cpp View File

@@ -0,0 +1,209 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#define BUFSIZE 4096 //minimum 2 buffere de mp3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MP3InputS.h"
using namespace std;


MP3InputS::MP3InputS(){
info.nsamples=0;
info.nchannels=2;
info.samplerate=44100;
info.currentsample=0;
eof=false;
MP3_opened=false;
f=NULL;
buf=NULL;
};

MP3InputS::~MP3InputS(){
close();
};

bool MP3InputS::open(string filename){
pcm_remained=0;
close();//inchide un posibil fisier existent
eof=true;
f=fopen(filename.c_str(),"rb");
if (!f) return false;
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);

buf=new unsigned char[BUFSIZE];

MP3_opened=true;
eof=false;

fseek(f,0,SEEK_END);
info.nsamples=ftell(f);
rewind(f);
info.currentsample=0;
info.samplerate=44100;

{//find the samplerate
const int n=8192;
short int tmpsmp[n*2];
read(n,tmpsmp);//read just a sample (and ignore it) to fill info.samplerate
seek(0);
pcm_remained=0;
info.currentsample=0;
//reinit the mad
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
};

info.nchannels=2;
return true;
};

void MP3InputS::close(){
if (MP3_opened){
MP3_opened=false;
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
delete [] buf;
fclose(f);
f=NULL;
};
};


int MP3InputS::read(int nsmps,short int *smps){
int orig_nsmps=nsmps;
short int *orig_smps=smps;
if (!MP3_opened) {
eof=true;
return 0;
};
if (eof) {
for (int i=0;i<nsmps;i++) smps[i]=0;
return nsmps;
};

if (pcm_remained>0){
int nconverted=pcm_remained;
if (nconverted>nsmps) nconverted=nsmps;
convertsmps(nconverted,smps,synth.pcm.length-pcm_remained);

nsmps-=nconverted;
smps+=nconverted*2;

if (nsmps<=0){
pcm_remained-=orig_nsmps;
return orig_nsmps;
};
};

while (nsmps>0){
int remaining=0;
if (stream.next_frame!=NULL){
remaining=stream.bufend-stream.next_frame;
memmove(buf,stream.next_frame,remaining);
};
int readsize=BUFSIZE-remaining;
int readed=fread(buf+remaining,1,readsize,f);
if (feof(f)) eof=true;
if ((eof) || (readed<1)){
for (int i=0;i<orig_nsmps;i++){
orig_smps[i]=0;
};
return orig_nsmps;
};
info.currentsample+=readed;


if (readed!=readsize) {
for (int i=readed;i<readsize;i++) buf[i+remaining]=0;
};
mad_stream_buffer(&stream, buf, BUFSIZE);
while(1){
if (mad_frame_decode(&frame, &stream)!=0){
if (stream.error==MAD_ERROR_BUFLEN) break;
if (stream.error==MAD_ERROR_LOSTSYNC) continue;
if (!MAD_RECOVERABLE(stream.error)) {
printf("Non recoverable MP3 error: 0x%x\n",stream.error);///in caz ca nu este recuperabil
close();
return orig_nsmps;
};
};
mad_synth_frame(&synth, &frame);

int n=synth.pcm.length;
if (synth.pcm.samplerate!=0) info.samplerate=synth.pcm.samplerate;
if (nsmps<synth.pcm.length){
pcm_remained=synth.pcm.length-nsmps;
n=nsmps;
}else{
pcm_remained=0;
};

convertsmps(n,smps,0);
nsmps-=n;
smps+=n*2;
if (nsmps<=0) return orig_nsmps;
};
};

return orig_nsmps;
};
void MP3InputS::convertsmps(int nsmps, short int *smps,int pcmstart){
mad_fixed_t *l=synth.pcm.samples[0],*r=synth.pcm.samples[0];
if (synth.pcm.channels==2) r=synth.pcm.samples[1];
l+=pcmstart;r+=pcmstart;
for (int i=0;i<nsmps;i++){//todo optimize (avoid reconverting r[] for mono samples)
smps[i*2]=madpcm2short(l[i]);
smps[i*2+1]=madpcm2short(r[i]);
};
};


short int MP3InputS::madpcm2short(mad_fixed_t x){
if (x>=MAD_F_ONE) x=MAD_F_ONE-1;
else if (x<=-MAD_F_ONE) x=-MAD_F_ONE+1;
int result= x >> (MAD_F_FRACBITS + 1 - 16);
return result;
};

void MP3InputS::seek(double pos){
if (!MP3_opened) return;
pcm_remained=0;

int p=(int)(pos*info.nsamples);
info.currentsample=p;
fseek(f,p,SEEK_SET);
/* if (p==0) {
fseek(f,0,SEEK_SET);
}else{
//todo add other thing here
fseek(f,p,SEEK_SET);
};
*/
};


+ 51
- 0
Input/MP3InputS.h View File

@@ -0,0 +1,51 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef MP3_INPUT_H
#define MP3_INPUT_H
#include <string>
#include <stdio.h>
#include <mad.h>
#include "InputS.h"


class MP3InputS:public InputS{
public:
MP3InputS();
~MP3InputS();
bool open(std::string filename);
void close();

int read(int nsmps,short int *smps);
void seek(double pos);//0=start,1.0=end
private:
void convertsmps(int nsmps, short int *smps,int pcmstart);
short int madpcm2short(mad_fixed_t x);
int pcm_remained;
bool MP3_opened;
struct mad_stream stream;
struct mad_frame frame;
struct mad_synth synth;
FILE *f;
unsigned char *buf;
};
#endif

+ 137
- 0
Input/VorbisInputS.cpp View File

@@ -0,0 +1,137 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


#define BUFSIZE 4096

#include <stdio.h>
#include <stdlib.h>
#include "VorbisInputS.h"
using namespace std;



VorbisInputS::VorbisInputS(){
info.nsamples=0;
info.nchannels=0;
info.samplerate=1;
info.currentsample=0;
eof=false;
vorbis_opened=false;
real_channels=1;
buf=NULL;
bufsize=0;
};

VorbisInputS::~VorbisInputS(){
close();
};

bool VorbisInputS::open(string filename){
close();//inchide un posibil fisier existent
eof=true;
FILE *f=fopen(filename.c_str(),"rb");
if (!f) return false;

int result=ov_open(f,&vorbisfile,NULL,0);
if (result<0){
fclose(f);
return false;
};
vorbis_opened=true;
vorbis_info *vinfo=ov_info(&vorbisfile,0);
if (!vinfo) return false;
real_channels=vinfo->channels;
if ((real_channels!=1)&&(real_channels!=2))return false;//only mono&stereo oggs are allowed
info.nsamples=ov_pcm_total(&vorbisfile,0);
info.nchannels=2;
bufsize=real_channels*BUFSIZE;
buf=new short int[bufsize];
info.samplerate=vinfo->rate;
info.currentsample=0;
eof=false;
return(true);
};

void VorbisInputS::close(){
if (vorbis_opened){
delete [] buf;
ov_clear(&vorbisfile);
vorbis_opened=false;
};
};

int VorbisInputS::read(int nsmps,short int *smps){
if (!vorbis_opened) {
eof=true;
return 0;
};
if (eof) {
for (int i=0;i<nsmps;i++) smps[i]=0;
return nsmps;
};

int current_section=0;
int nsmps_todo=nsmps;
int nsmps_done=0;
short int *smps_orig=smps;
while (nsmps_todo>=0){
int chunk_size=(nsmps_todo<BUFSIZE)?nsmps_todo:BUFSIZE;
if (chunk_size==0) break;
int readed=ov_read(&vorbisfile,(char *)buf,chunk_size*sizeof(short int)*real_channels,0,2,1,&current_section);
if ((readed<=0)||(current_section!=0)){
eof=true;
for (int i=0;i<nsmps_todo;i++) smps[i]=0;
return nsmps;
};
readed/=sizeof(short int);//from bytes to short int samples
switch(real_channels){
case 1:
for (int i=0;i<readed;i++){
smps[i*2]=smps[i*2+1]=buf[i];
};
smps+=readed*2;
nsmps_done+=readed;
nsmps_todo-=readed;
break;
case 2:
for (int i=0;i<readed;i++){
smps[i]=buf[i];
};
nsmps_done+=readed/2;
nsmps_todo-=readed/2;
smps+=readed;
break;
};
info.currentsample+=readed/real_channels;
};
return nsmps;
};

void VorbisInputS::seek(double pos){
if (!vorbis_opened) return;
long int p=(long int)(pos*info.nsamples);
ov_pcm_seek(&vorbisfile,p);
info.currentsample=p;
};


+ 45
- 0
Input/VorbisInputS.h View File

@@ -0,0 +1,45 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef VORBIS_INPUT_H
#define VORBIS_INPUT_H
#include <string>
#include <vorbis/vorbisfile.h>

#include "InputS.h"

class VorbisInputS:public InputS{
public:
VorbisInputS();
~VorbisInputS();
bool open(std::string filename);
void close();

int read(int nsmps,short int *smps);
void seek(double pos);//0=start,1.0=end
private:
OggVorbis_File vorbisfile;
bool vorbis_opened;
int real_channels;

short int *buf;
int bufsize;
};
#endif

+ 243
- 0
JAaudiooutput.cpp View File

@@ -0,0 +1,243 @@
/*
JAaudiooutput.C - Audio output for JACK
Copyright (C) 2002-2009 Nasca Octavian Paul
Author: Robin Gareus <robin@gareus.org>

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifdef HAVE_JACK

#ifndef DEFAULT_RB_SIZE
#define DEFAULT_RB_SIZE 16384
#endif

#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include "JAaudiooutput.h"

Player *myplayer=NULL;
jack_client_t *j_client = NULL;
jack_port_t **j_output_port = NULL;
jack_default_audio_sample_t **j_out = NULL;
jack_ringbuffer_t *rb = NULL;

int m_channels = 2;
int thread_run = 0;

pthread_t player_thread_id;
pthread_mutex_t player_thread_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t buffer_ready = PTHREAD_COND_INITIALIZER;

#ifdef ENABLE_RESAMPLING
#include <samplerate.h>
float m_fResampleRatio = 1.0;

#ifndef SRC_QUALITY // alternatives: SRC_SINC_MEDIUM_QUALITY, SRC_SINC_BEST_QUALITY, (SRC_ZERO_ORDER_HOLD, SRC_LINEAR)
#define SRC_QUALITY SRC_SINC_FASTEST
#endif

#endif

void jack_shutdown_callback(void *arg){
fprintf(stderr, "jack server [unexpectedly] shut down.\n");
j_client=NULL;
JACKclose();
}

int jack_audio_callback(jack_nframes_t nframes, void *arg){
int c,s;

for(c=0; c< m_channels; c++) {
j_out[c] = (jack_default_audio_sample_t*) jack_port_get_buffer(j_output_port[c], nframes);
}

if(jack_ringbuffer_read_space(rb) < m_channels * nframes * sizeof(jack_default_audio_sample_t)) {
for(c=0; c< m_channels; c++) {
memset(j_out[c], 0, nframes * sizeof(jack_default_audio_sample_t));
}
} else {
/* de-interleave */
for(s=0; s<nframes; s++) {
for(c=0; c< m_channels; c++) {
jack_ringbuffer_read(rb, (char*) &j_out[c][s], sizeof(jack_default_audio_sample_t));
}
}
}

/* Tell the player thread there is work to do. */
if(pthread_mutex_trylock(&player_thread_lock) == 0) {
pthread_cond_signal(&buffer_ready);
pthread_mutex_unlock(&player_thread_lock);
}

return(0);
};

void *jack_player_thread(void *){
const int nframes = 4096;
float *tmpbuf = (float*) calloc(nframes * m_channels, sizeof(float));
float *bufptr = tmpbuf;
#ifdef ENABLE_RESAMPLING
SRC_STATE* src_state = src_new(SRC_QUALITY, 2, NULL);
SRC_DATA src_data;
int nframes_r = floorf((float) nframes*m_fResampleRatio); ///< # of frames after resampling
float *smpbuf = (float*) calloc((1+nframes_r) * m_channels, sizeof(float));

src_data.input_frames = nframes;
src_data.output_frames = nframes_r;
src_data.end_of_input = 0;
src_data.src_ratio = m_fResampleRatio;
src_data.input_frames_used = 0;
src_data.output_frames_gen = 0;
src_data.data_in = tmpbuf;
src_data.data_out = smpbuf;
#else
int nframes_r = nframes;
#endif

size_t rbsize = nframes_r * m_channels * sizeof(float);

pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock(&player_thread_lock);

while(thread_run) {
myplayer->getaudiobuffer(nframes, tmpbuf);

#ifdef ENABLE_RESAMPLING
if(m_fResampleRatio != 1.0) {
src_process(src_state, &src_data);
bufptr = smpbuf;
rbsize = src_data.output_frames_gen * m_channels * sizeof(float);
}
#endif
jack_ringbuffer_write(rb, (char *) bufptr, rbsize);

while(thread_run && jack_ringbuffer_write_space(rb) <= rbsize) {
pthread_cond_wait(&buffer_ready, &player_thread_lock);
}
}

pthread_mutex_unlock(&player_thread_lock);
free(tmpbuf);
#ifdef ENABLE_RESAMPLING
src_delete(src_state);
free(smpbuf);
#endif
}

void JACKaudiooutputinit(Player *player_, int samplerate){
int i;
myplayer=player_;

if(j_client || thread_run || rb) {
fprintf(stderr, "already connected to jack.\n");
return;
}

j_client = jack_client_open("paulstretch", (jack_options_t) 0, NULL);

if(!j_client) {
fprintf(stderr, "could not connect to jack.\n");
return;
}

jack_on_shutdown(j_client, jack_shutdown_callback, NULL);
jack_set_process_callback(j_client, jack_audio_callback, NULL);

j_output_port=(jack_port_t**) calloc(m_channels, sizeof(jack_port_t*));

for(i=0;i<m_channels;i++) {
char channelid[16];
snprintf(channelid, 16, "output_%i", i);
j_output_port[i] = jack_port_register(j_client, channelid, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if(!j_output_port[i]) {
fprintf(stderr, "no more jack ports availabe.\n");
JACKclose();
return;
}
}

j_out = (jack_default_audio_sample_t**) calloc(m_channels, sizeof(jack_default_audio_sample_t*));
const size_t rbsize = DEFAULT_RB_SIZE * m_channels * sizeof(jack_default_audio_sample_t);
rb = jack_ringbuffer_create(rbsize);
memset(rb->buf, 0, rbsize);

jack_nframes_t jsr = jack_get_sample_rate(j_client);
if(jsr != samplerate) {
#ifdef ENABLE_RESAMPLING
m_fResampleRatio = (float) jsr / (float) samplerate;
#else
fprintf(stderr, "Note: paulstretch audio samplerate does not match JACK's samplerate.\n");
#endif
}

thread_run = 1;
pthread_create(&player_thread_id, NULL, jack_player_thread, NULL);
pthread_yield();

jack_activate(j_client);

char *jack_autoconnect = getenv("JACK_AUTOCONNECT");
if(!jack_autoconnect) {
jack_autoconnect = (char*) "system:playback_";
} else if(!strncmp(jack_autoconnect,"DISABLE", 7)) {
jack_autoconnect = NULL;
}
if(jack_autoconnect) {
int myc=0;
const char **found_ports = jack_get_ports(j_client, jack_autoconnect, NULL, JackPortIsInput);
for(i = 0; found_ports && found_ports[i]; i++) {
if(jack_connect(j_client, jack_port_name(j_output_port[myc]), found_ports[i])) {
fprintf(stderr, "can not connect to jack output\n");
}
if(myc >= m_channels) break;
}
}
}

void JACKclose(){
if(thread_run) {
thread_run = 0;
if(pthread_mutex_trylock(&player_thread_lock) == 0) {
pthread_cond_signal(&buffer_ready);
pthread_mutex_unlock(&player_thread_lock);
}
pthread_join(player_thread_id, NULL);
}
if(j_client){
jack_client_close(j_client);
}
if(j_output_port) {
free(j_output_port);
j_output_port=NULL;
}
if(j_out) {
free(j_out);
j_out = NULL;
}
if(rb) {
jack_ringbuffer_free(rb);
rb=NULL;
}
j_client=NULL;
};

#endif /* HAVE_JACK */

/* vim: set ts=8 sw=4: */

+ 34
- 0
JAaudiooutput.h View File

@@ -0,0 +1,34 @@
/*
JAaudiooutput.h - Audio output for JACK
Copyright (C) 2002 Nasca Octavian Paul
Author: Robin Gareus <robin@gareus.org>

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef JACK_AUDIO_OUTPUT_H
#define JACK_AUDIO_OUTPUT_H

#ifdef HAVE_JACK

#include "Player.h"


void JACKaudiooutputinit(Player *player_,int samplerate);
void JACKclose();

#endif
#endif

/* vim: set ts=8 sw=4: */

+ 51
- 0
Mutex.cpp View File

@@ -0,0 +1,51 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Mutex.h"
Mutex::Mutex(){
#ifdef WINDOWS
InitializeCriticalSection(&mutex);
#else
pthread_mutex_init(&mutex,NULL);
#endif
};

Mutex::~Mutex(){
#ifdef WINDOWS
DeleteCriticalSection(&mutex);
#else
pthread_mutex_destroy(&mutex);
#endif
};


void Mutex::lock(){
#ifdef WINDOWS
EnterCriticalSection(&mutex);
#else
pthread_mutex_lock(&mutex);
#endif
};

void Mutex::unlock(){
#ifdef WINDOWS
LeaveCriticalSection(&mutex);
#else
pthread_mutex_unlock(&mutex);
#endif
};


+ 44
- 0
Mutex.h View File

@@ -0,0 +1,44 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MUTEX_H
#define MUTEX_H

#ifdef WINDOWS
#include <windows.h>
#include <winbase.h>
#else
#include <pthread.h>
#endif

class Mutex{
public:
Mutex();
~Mutex();
void lock();
void unlock();
private:
#ifdef WINDOWS
CRITICAL_SECTION mutex;
#else
pthread_mutex_t mutex;
#endif
};


#endif


+ 62
- 0
Output/AOutputS.cpp View File

@@ -0,0 +1,62 @@
/*
Copyright (C) 2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdio.h>
#include <stdlib.h>
#include "AOutputS.h"
using namespace std;

AOutputS::AOutputS(){
handle=AF_NULL_FILEHANDLE;
};

AOutputS::~AOutputS(){
close();
};

bool AOutputS::newfile(string filename,int samplerate,bool use32bit){
close();//inchide un posibil fisier existent

AFfilesetup afsetup=afNewFileSetup();
if (use32bit) afInitSampleFormat(afsetup,AF_DEFAULT_TRACK,AF_SAMPFMT_TWOSCOMP,32);
afInitChannels(afsetup,AF_DEFAULT_TRACK,2);
afInitRate(afsetup,AF_DEFAULT_TRACK,samplerate);
handle=afOpenFile(filename.c_str(),"w",afsetup);
if (handle==AF_NULL_FILEHANDLE){//eroare
afFreeFileSetup(afsetup);
return(false);
};
afSetVirtualSampleFormat(handle,AF_DEFAULT_TRACK,AF_SAMPFMT_TWOSCOMP,32);
afFreeFileSetup(afsetup);
return(true);
};

void AOutputS::close(){
if (handle!=AF_NULL_FILEHANDLE){
afCloseFile(handle);
handle=AF_NULL_FILEHANDLE;
};
};

void AOutputS::write(int nsmps,int *smps){
if (handle==AF_NULL_FILEHANDLE) return;
afWriteFrames(handle,AF_DEFAULT_TRACK,smps,nsmps);
};


+ 41
- 0
Output/AOutputS.h View File

@@ -0,0 +1,41 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef AOUTPUT_H
#define AOUTPUT_H
#include <string>
#include <audiofile.h>

class AOutputS{
public:
AOutputS();
~AOutputS();
bool newfile(std::string filename,int samplerate,bool use32bit=false);
void close();

void write(int nsmps, int *smps);
struct {
int nsamples;
} info;
private:
AFfilehandle handle;
};
#endif

+ 126
- 0
Output/VorbisOutputS.cpp View File

@@ -0,0 +1,126 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul and the Vorbis authors
Author: Nasca Octavian Paul and Vorbis authors (XIPHOPHORUS Company)
(some lines of code took from encoder_example.c from vorbis library)

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdlib.h>
#include "VorbisOutputS.h"
using namespace std;

VorbisOutputS::VorbisOutputS(){
outfile=NULL;
opened=false;
};

VorbisOutputS::~VorbisOutputS(){
close();
};

bool VorbisOutputS::newfile(string filename,int samplerate,REALTYPE quality){
close();//inchide un posibil fisier existent


outfile=fopen(filename.c_str(),"wb");
if (!outfile) return false;

vorbis_info_init(&vi);
int ret=vorbis_encode_init_vbr(&vi,2,samplerate,quality/10.0);
if (ret) return false;
//adaug comentariu
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc,"program","PaulStretch by Nasca Octavian PAUL");

//setari analiza
vorbis_analysis_init(&vd,&vi);
vorbis_block_init(&vd,&vb);
ogg_stream_init(&os,0x3FB771E2);

ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;

vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
ogg_stream_packetin(&os,&header);
ogg_stream_packetin(&os,&header_comm);
ogg_stream_packetin(&os,&header_code);

int eos=0;
while(!eos){
int result=ogg_stream_flush(&os,&og);
if(result==0)break;
int tmp=0;
tmp=fwrite(og.header,1,og.header_len,outfile);
tmp=fwrite(og.body,1,og.body_len,outfile);
};


opened=true;
return(true);
};

void VorbisOutputS::close(){
if (!opened) return;
write(0,NULL,NULL);//scriu un pachet de EOS
fclose(outfile);
ogg_stream_clear(&os);
vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
opened=false;
};

void VorbisOutputS::write(int nsmps,REALTYPE *smpsl,REALTYPE *smpsr){
if (!opened) return;

if (nsmps!=0){
float **buffer=vorbis_analysis_buffer(&vd,nsmps);
int i=0;
for (i=0;i<nsmps;i++){
buffer[0][i]=smpsl[i];
buffer[1][i]=smpsr[i];
};
};
vorbis_analysis_wrote(&vd,nsmps);

while(vorbis_analysis_blockout(&vd,&vb)==1){

vorbis_analysis(&vb,NULL);
vorbis_bitrate_addblock(&vb);

while(vorbis_bitrate_flushpacket(&vd,&op)){
ogg_stream_packetin(&os,&op);
int eos=0;
while (!eos){
int result=ogg_stream_pageout(&os,&og);
if(result==0)break;
int tmp;
tmp=fwrite(og.header,1,og.header_len,outfile);
tmp=fwrite(og.body,1,og.body_len,outfile);
if(ogg_page_eos(&og))eos=1;
};
};
};

};


+ 53
- 0
Output/VorbisOutputS.h View File

@@ -0,0 +1,53 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef VORBISOUTPUT_H
#define VORBISOUTPUT_H
#include <string>
#include <stdio.h>
#include <vorbis/vorbisenc.h>
#ifndef REALTYPE
#define REALTYPE float
#endif

class VorbisOutputS{
public:
VorbisOutputS();
~VorbisOutputS();
bool newfile(std::string filename,int samplerate,REALTYPE quality=3.5);//quality 0.0-10.0
void close();

void write(int nsmps, REALTYPE *smpsl,REALTYPE *smpr);
private:
bool opened;

ogg_stream_state os;
ogg_page og;
ogg_packet op;
vorbis_info vi;
vorbis_comment vc;

vorbis_dsp_state vd;
vorbis_block vb;
FILE *outfile;
};
#endif

+ 56
- 0
PAaudiooutput.cpp View File

@@ -0,0 +1,56 @@
/*
PAaudiooutput.C - Audio output for PortAudio
Copyright (C) 2002-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <stdlib.h>
#include "PAaudiooutput.h"

Player *player=NULL;
PaStream *stream=NULL;

static int PAprocess(const void *inputBuffer,void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *outTime,PaStreamCallbackFlags statusFlags,void *userData){
float *out=(float *)outputBuffer;
player->getaudiobuffer(framesPerBuffer,out);

return(0);
};

void PAaudiooutputinit(Player *player_,int samplerate){
player=player_;
if (stream) return;
Pa_Initialize();
Pa_OpenDefaultStream(&stream,0,2,paFloat32,samplerate,PA_SOUND_BUFFER_SIZE,PAprocess,NULL);
Pa_StartStream(stream);
};

void PAfinish(){
if (stream){
Pa_StopStream(stream);
Pa_CloseStream(stream);
Pa_Terminate();
};
stream=NULL;

};





+ 31
- 0
PAaudiooutput.h View File

@@ -0,0 +1,31 @@
/*
PAaudiooutput.h - Audio output for PortAudio
Copyright (C) 2002 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef PA_AUDIO_OUTPUT_H
#define PA_AUDIO_OUTPUT_H

#include <portaudio.h>
#include "Player.h"


void PAaudiooutputinit(Player *player_,int samplerate);
void PAfinish();

#endif


+ 439
- 0
Player.cpp View File

@@ -0,0 +1,439 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include "Player.h"
#include "globals.h"

static int player_count=0;

Player::Player():Thread(){
player_count++;
if (player_count>1) {
printf("Error: Player class multiples instances.\n");
exit(1);
};

stretchl=NULL;
stretchr=NULL;
binaural_beats=NULL;

ai=NULL;

newtask.mode=TASK_NONE;
newtask.startpos=0.0;
newtask.rap=1.0;
newtask.fftsize=4096;

task=newtask;
mode=MODE_STOP;

outbuf.n=0;
outbuf.datal=NULL;
outbuf.datar=NULL;
outbuf.size=0;
outbuf.computek=0;
outbuf.outk=0;
outbuf.outpos=0;
outbuf.nfresh=0;
outbuf.in_position=0;
inbuf_i=NULL;
info.position=0;
freeze_mode=false;
bypass_mode=false;
first_in_buf=true;
window_type=W_HANN;
inbuf.l=NULL;
inbuf.r=NULL;

paused=false;

info.playing=false;
info.samplerate=44100;
info.eof=true;
volume=1.0;
};

Player::~Player(){
player_count--;

stop();
if (stretchl) delete stretchl;stretchl=NULL;
if (stretchr) delete stretchr;stretchr=NULL;
if (outbuf.in_position) delete outbuf.in_position;
if (inbuf.l) delete inbuf.l;
if (inbuf.r) delete inbuf.r;
if (inbuf_i) delete inbuf_i;
if (ai) delete ai;
if (binaural_beats) delete binaural_beats;binaural_beats=NULL;
};

Player::ModeType Player::getmode(){
return mode;
};

void Player::startplay(std::string filename, REALTYPE startpos,REALTYPE rap, int fftsize,FILE_TYPE intype,bool bypass,ProcessParameters *ppar,BinauralBeatsParameters *bbpar){
info.playing=false;
info.eof=false;
bypass_mode=bypass;
if (bypass) freeze_mode=false;
paused=false;
taskmutex.lock();
newtask.mode=TASK_START;
newtask.filename=filename;
newtask.startpos=startpos;
newtask.rap=rap;
newtask.fftsize=fftsize;
newtask.intype=intype;
newtask.bypass=bypass;
newtask.ppar=ppar;
newtask.bbpar=bbpar;
taskmutex.unlock();
};

void Player::stop(){
//pun 0 la outbuf
info.playing=false;
/* taskmutex.lock();
newtask.mode=TASK_STOP;
taskmutex.unlock();*/
};
void Player::pause(){
paused=!paused;
};

void Player::seek(REALTYPE pos){
taskmutex.lock();
newtask.mode=TASK_SEEK;
newtask.startpos=pos;
taskmutex.unlock();
};
void Player::freeze(){
freeze_mode=!freeze_mode;
if (bypass_mode) freeze_mode=false;
};

void Player::setrap(REALTYPE newrap){
taskmutex.lock();
newtask.mode=TASK_RAP;
newtask.rap=newrap;
taskmutex.unlock();
};

void Player::set_process_parameters(ProcessParameters *ppar,BinauralBeatsParameters *bbpar){
taskmutex.lock();
newtask.mode=TASK_PARAMETERS;
newtask.ppar=ppar;
newtask.bbpar=bbpar;
taskmutex.unlock();
};


void Player::set_window_type(FFTWindow window){
window_type=window;
};

void Player::set_volume(REALTYPE vol){
volume=vol;
};

void Player::getaudiobuffer(int nsamples, float *out){
if (mode==MODE_PREPARING){
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};
if (paused){
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};

bufmutex.lock();
if ((outbuf.n==0)||(outbuf.nfresh==0)){
bufmutex.unlock();
for (int i=0;i<nsamples*2;i++){
out[i]=0.0;
};
return;
};
int k=outbuf.outk,pos=outbuf.outpos;

// printf("%d in_pos=%g\n",info.eof,outbuf.in_position[k]);
if (info.eof) mode=MODE_STOP;
else info.position=outbuf.in_position[k];
for (int i=0;i<nsamples;i++){
out[i*2]=outbuf.datal[k][pos]*volume;
out[i*2+1]=outbuf.datar[k][pos]*volume;

pos++;
if (pos>=outbuf.size) {
pos=0;
k++;
if (k>=outbuf.n) k=0;

outbuf.nfresh--;
//printf("%d %d\n",k,outbuf.nfresh);

if (outbuf.nfresh<0){//Underflow
outbuf.nfresh=0;
for (int j=i;j<nsamples;j++){
out[j*2]=0.0;
out[j*2+1]=0.0;
};
break;
};

};
};
// printf("-------------- %d\n",outbuf.nfresh);
outbuf.outk=k;
outbuf.outpos=pos;
bufmutex.unlock();

// printf("max=%g\n",max);

};


void Player::run(){
while(1){
newtaskcheck();

if (mode==MODE_STOP) sleep(10);
if ((mode==MODE_PLAY)||(mode==MODE_PREPARING)){
computesamples();
};


task.mode=TASK_NONE;

};
};

void Player::newtaskcheck(){
TaskMode newmode=TASK_NONE;
taskmutex.lock();
if (task.mode!=newtask.mode) {
newmode=newtask.mode;
task=newtask;
};
newtask.mode=TASK_NONE;
taskmutex.unlock();

if (newmode==TASK_START){
if (current_filename!=task.filename){
current_filename=task.filename;
task.startpos=0.0;
};
switch (task.intype){
case FILE_VORBIS:ai=new VorbisInputS;
break;
case FILE_MP3:ai=new MP3InputS;
break;
default: ai=new AInputS;
};
if (ai->open(task.filename)){
info.samplerate=ai->info.samplerate;
mode=MODE_PREPARING;
ai->seek(task.startpos);

bufmutex.lock();

if (stretchl) delete stretchl;stretchl=NULL;
if (stretchr) delete stretchr;stretchr=NULL;
stretchl=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,1);
stretchr=new ProcessedStretch(task.rap,task.fftsize,window_type,task.bypass,ai->info.samplerate,2);
if (binaural_beats) delete binaural_beats;binaural_beats=NULL;
binaural_beats=new BinauralBeats(ai->info.samplerate);

if (stretchl) stretchl->set_parameters(task.ppar);
if (stretchr) stretchr->set_parameters(task.ppar);
if (binaural_beats) binaural_beats->pars=*(task.bbpar);

inbufsize=stretchl->poolsize;
if (inbuf.l) delete []inbuf.l;inbuf.l=NULL;
if (inbuf.r) delete []inbuf.r;inbuf.r=NULL;
inbuf.l=new REALTYPE[inbufsize];
inbuf.r=new REALTYPE[inbufsize];
for (int i=0;i<inbufsize;i++) inbuf.l[i]=inbuf.r[i]=0.0;

if (outbuf.datal){
for (int j=0;j<outbuf.n;j++){
delete [] outbuf.datal[j];
};
delete [] outbuf.datal;
outbuf.datal=NULL;
};
if (outbuf.datar){
for (int j=0;j<outbuf.n;j++){
delete [] outbuf.datar[j];
};
delete [] outbuf.datar;
outbuf.datar=NULL;
};
delete[] inbuf_i;

if (outbuf.in_position) {
delete outbuf.in_position;
outbuf.in_position=NULL;
};

inbuf_i=new short int[inbufsize*2];//for left and right
for (int i=0;i<inbufsize;i++){
inbuf_i[i*2]=inbuf_i[i*2+1]=0;
};
first_in_buf=true;

outbuf.size=stretchl->out_bufsize;

int min_samples=ai->info.samplerate*2;
int n=2*PA_SOUND_BUFFER_SIZE/outbuf.size;
if (n<3) n=3;//min 3 buffers
if (n<(min_samples/outbuf.size)) n=(min_samples/outbuf.size);//the internal buffers sums "min_samples" amount
// printf("PA_BUFSIZE=%d out_bufsize=%d => %d\n",PA_SOUND_BUFFER_SIZE,outbuf.size,n);

outbuf.n=n;
outbuf.nfresh=0;
outbuf.datal=new float *[outbuf.n];
outbuf.datar=new float *[outbuf.n];
outbuf.computek=0;
outbuf.outk=0;
outbuf.outpos=0;
outbuf.in_position=new float[outbuf.n];
for (int j=0;j<outbuf.n;j++){
outbuf.datal[j]=new float[outbuf.size];
for (int i=0;i<outbuf.size;i++) outbuf.datal[j][i]=0.0;
outbuf.datar[j]=new float[outbuf.size];
for (int i=0;i<outbuf.size;i++) outbuf.datar[j][i]=0.0;
outbuf.in_position[j]=0.0;
};

bufmutex.unlock();

};
};
if (newmode==TASK_SEEK){
if (ai) ai->seek(task.startpos);
first_in_buf=true;
};
if (newmode==TASK_RAP){
if (stretchl) stretchl->set_rap(task.rap);
if (stretchl) stretchr->set_rap(task.rap);
};
if (newmode==TASK_PARAMETERS){
if (stretchl) stretchl->set_parameters(task.ppar);
if (stretchr) stretchr->set_parameters(task.ppar);
if (binaural_beats) binaural_beats->pars=*(task.bbpar);
};
};

void Player::computesamples(){
bufmutex.lock();
bool exitnow=(outbuf.n==0);
if (outbuf.nfresh>=(outbuf.n-1)) exitnow=true;//buffers are full

bufmutex.unlock();
if (exitnow) {
if (mode==MODE_PREPARING) {
info.playing=true;
mode=MODE_PLAY;
};
sleep(10);
return;
};

bool eof=false;
if (!ai) eof=true;
else if (ai->eof) eof=true;
if (eof){
for (int i=0;i<inbufsize;i++){
inbuf_i[i*2]=inbuf_i[i*2+1]=0;
};
outbuf.nfresh++;
bufmutex.lock();
for (int i=0;i<outbuf.size;i++){
outbuf.datal[outbuf.computek][i]=0.0;
outbuf.datar[outbuf.computek][i]=0.0;
};
outbuf.computek++;
if (outbuf.computek>=outbuf.n){
outbuf.computek=0;
};
bufmutex.unlock();
info.eof=true;
return;
};

bool result=true;
float in_pos_100=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples*100.0;
int readsize=stretchl->get_nsamples(in_pos_100);
if (freeze_mode) readsize=0;


if (first_in_buf) readsize=stretchl->get_nsamples_for_fill();
if (readsize) result=(ai->read(readsize,inbuf_i)==(readsize));
if (result){
float in_pos=(REALTYPE) ai->info.currentsample/(REALTYPE)ai->info.nsamples;
if (ai->eof) in_pos=0.0;

REALTYPE tmp=1.0/32768.0;
for (int i=0;i<readsize;i++){
inbuf.l[i]=inbuf_i[i*2]*tmp;
inbuf.r[i]=inbuf_i[i*2+1]*tmp;
};

first_in_buf=false;
stretchl->window_type=window_type;
stretchr->window_type=window_type;
stretchl->process(inbuf.l,readsize);
stretchr->process(inbuf.r,readsize);
binaural_beats->process(stretchl->out_buf,stretchr->out_buf,stretchl->out_bufsize,in_pos_100);
// stretchl->process_output(stretchl->out_buf,stretchl->out_bufsize);
// stretchr->process_output(stretchr->out_buf,stretchr->out_bufsize);

bufmutex.lock();

for (int i=0;i<outbuf.size;i++){
REALTYPE l=stretchl->out_buf[i],r=stretchr->out_buf[i];
if (l<-1.0) l=-1.0;
else if (l>1.0) l=1.0;
if (r<-1.0) r=-1.0;
else if (r>1.0) r=1.0;

outbuf.datal[outbuf.computek][i]=l;
outbuf.datar[outbuf.computek][i]=r;
};
outbuf.in_position[outbuf.computek]=in_pos;
outbuf.computek++;
if (outbuf.computek>=outbuf.n){
outbuf.computek=0;
};
bufmutex.unlock();
outbuf.nfresh++;
}else{
info.eof=true;
mode=MODE_STOP;
stop();
};
};


+ 130
- 0
Player.h View File

@@ -0,0 +1,130 @@
/*
Copyright (C) 2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PLAYER_H
#define PLAYER_H

#include <string>
#include "Input/AInputS.h"
#include "Input/VorbisInputS.h"
#include "Input/MP3InputS.h"
#include "ProcessedStretch.h"
#include "Thread.h"
#include "BinauralBeats.h"
#include "Mutex.h"
#include "globals.h"

#define PA_SOUND_BUFFER_SIZE 8192


class Player:public Thread{
public:
Player();
~Player();
void startplay(std::string filename, REALTYPE startpos,REALTYPE rap, int fftsize,FILE_TYPE intype,bool bypass,ProcessParameters *ppar,BinauralBeatsParameters *bbpar);
//startpos is from 0 (start) to 1.0 (end of file)
void stop();
void pause();
void freeze();
void setrap(REALTYPE newrap);
void seek(REALTYPE pos);
void getaudiobuffer(int nsamples, float *out);//data este stereo
enum ModeType{
MODE_PLAY,MODE_STOP,MODE_PREPARING,MODE_PAUSE
};
ModeType getmode();
struct{
float position;//0 is for start, 1 for end
int playing;
int samplerate;
bool eof;
}info;

bool is_freeze(){
return freeze_mode;
};
void set_window_type(FFTWindow window);
void set_volume(REALTYPE vol);
void set_process_parameters(ProcessParameters *ppar,BinauralBeatsParameters *bbpar);
BinauralBeats *binaural_beats;

private:
void run();
InputS *ai;
ProcessedStretch *stretchl,*stretchr;

short int *inbuf_i;
int inbufsize;

Mutex taskmutex,bufmutex;
ModeType mode;
enum TaskMode{
TASK_NONE, TASK_START, TASK_STOP,TASK_SEEK,TASK_RAP,TASK_PARAMETERS
};
struct {
TaskMode mode;

REALTYPE startpos;
REALTYPE rap;
int fftsize;
std::string filename;
FILE_TYPE intype;
bool bypass;
ProcessParameters *ppar;
BinauralBeatsParameters *bbpar;
}newtask,task;
struct{
REALTYPE *l,*r;
}inbuf;
struct{
int n;//how many buffers
float **datal,**datar;//array of buffers
int size;//size of one buffer
int computek,outk;//current buffer
int outpos;//the sample position in the current buffer (for out)
int nfresh;//how many buffers are fresh added and need to be played
//nfresh==0 for empty buffers, nfresh==n-1 for full buffers
float *in_position;//the position(for input samples inside the input file) of each buffers
}outbuf;
bool first_in_buf;
void newtaskcheck();
void computesamples();
bool freeze_mode,bypass_mode,paused;
REALTYPE volume;

std::string current_filename;
FFTWindow window_type;
};

#endif


+ 434
- 0
ProcessedStretch.cpp View File

@@ -0,0 +1,434 @@
/*
Copyright (C) 2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "ProcessedStretch.h"

void ProcessParameters::add2XML(XMLwrapper *xml){

xml->addparbool("pitch_shift.enabled",pitch_shift.enabled);
xml->addparreal("pitch_shift.cents",pitch_shift.cents);

xml->addparbool("octave.enabled",octave.enabled);
xml->addparreal("octave.om2",octave.om2);
xml->addparreal("octave.om1",octave.om1);
xml->addparreal("octave.o0",octave.o0);
xml->addparreal("octave.o1",octave.o1);
xml->addparreal("octave.o15",octave.o15);
xml->addparreal("octave.o2",octave.o2);

xml->addparbool("freq_shift.enabled",freq_shift.enabled);
xml->addparreal("freq_shift.Hz",freq_shift.Hz);

xml->addparbool("compressor.enabled",compressor.enabled);
xml->addparreal("compressor.power",compressor.power);

xml->addparbool("filter.enabled",filter.enabled);
xml->addparbool("filter.stop",filter.stop);
xml->addparreal("filter.low",filter.low);
xml->addparreal("filter.high",filter.high);
xml->addparreal("filter.hdamp",filter.hdamp);

xml->addparbool("harmonics.enabled",harmonics.enabled);
xml->addparreal("harmonics.freq",harmonics.freq);
xml->addparreal("harmonics.bandwidth",harmonics.bandwidth);
xml->addpar("harmonic.nharmonics",harmonics.nharmonics);

xml->addparbool("harmonics.gauss",harmonics.gauss);

xml->addparbool("spread.enabled",spread.enabled);
xml->addparreal("spread.bandwidth",spread.bandwidth);

xml->beginbranch("FREE_FILTER");
free_filter.add2XML(xml);
xml->endbranch();

xml->beginbranch("STRETCH_MULTIPLIER");
stretch_multiplier.add2XML(xml);
xml->endbranch();

};

void ProcessParameters::getfromXML(XMLwrapper *xml){
pitch_shift.enabled=xml->getparbool("pitch_shift.enabled",pitch_shift.enabled);
pitch_shift.cents=xml->getparreal("pitch_shift.cents",pitch_shift.cents);

octave.enabled=xml->getparbool("octave.enabled",octave.enabled);
octave.om2=xml->getparreal("octave.om2",octave.om2);
octave.om1=xml->getparreal("octave.om1",octave.om1);
octave.o0=xml->getparreal("octave.o0",octave.o0);
octave.o1=xml->getparreal("octave.o1",octave.o1);
octave.o15=xml->getparreal("octave.o15",octave.o15);
octave.o2=xml->getparreal("octave.o2",octave.o2);

freq_shift.enabled=xml->getparbool("freq_shift.enabled",freq_shift.enabled);
freq_shift.Hz=xml->getparreal("freq_shift.Hz",freq_shift.Hz);

compressor.enabled=xml->getparbool("compressor.enabled",compressor.enabled);
compressor.power=xml->getparreal("compressor.power",compressor.power);

filter.enabled=xml->getparbool("filter.enabled",filter.enabled);
filter.stop=xml->getparbool("filter.stop",filter.stop);
filter.low=xml->getparreal("filter.low",filter.low);
filter.high=xml->getparreal("filter.high",filter.high);
filter.hdamp=xml->getparreal("filter.hdamp",filter.hdamp);

harmonics.enabled=xml->getparbool("harmonics.enabled",harmonics.enabled);
harmonics.freq=xml->getparreal("harmonics.freq",harmonics.freq);
harmonics.bandwidth=xml->getparreal("harmonics.bandwidth",harmonics.bandwidth);
harmonics.nharmonics=xml->getpar("harmonic.nharmonics",harmonics.nharmonics,1,100);

harmonics.gauss=xml->getparbool("harmonics.gauss",harmonics.gauss);

spread.enabled=xml->getparbool("spread.enabled",spread.enabled);
spread.bandwidth=xml->getparreal("spread.bandwidth",spread.bandwidth);

if (xml->enterbranch("FREE_FILTER")){
free_filter.getfromXML(xml);
xml->exitbranch();
};
if (xml->enterbranch("STRETCH_MULTIPLIER")){
stretch_multiplier.getfromXML(xml);
xml->exitbranch();
};
};

ProcessedStretch::ProcessedStretch(REALTYPE rap_,int in_bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_):Stretch(rap_,in_bufsize_,w,bypass_,samplerate_,stereo_mode_){
nfreq=out_bufsize;
infreq=new REALTYPE[nfreq];
sumfreq=new REALTYPE[nfreq];
tmpfreq1=new REALTYPE[nfreq];
tmpfreq2=new REALTYPE[nfreq];
free_filter_freqs=new REALTYPE[nfreq];
for (int i=0;i<nfreq;i++) free_filter_freqs[i]=1.0;
};
ProcessedStretch::~ProcessedStretch(){
delete [] infreq;
delete [] sumfreq;
delete [] tmpfreq1;
delete [] tmpfreq2;
delete [] free_filter_freqs;
};

void ProcessedStretch::set_parameters(ProcessParameters *ppar){
pars=*ppar;
update_free_filter();
};


void ProcessedStretch::copy(REALTYPE *freq1,REALTYPE *freq2){
for (int i=0;i<nfreq;i++) freq2[i]=freq1[i];
};

void ProcessedStretch::add(REALTYPE *freq2,REALTYPE *freq1,REALTYPE a){
for (int i=0;i<nfreq;i++) freq2[i]+=freq1[i]*a;
};

void ProcessedStretch::zero(REALTYPE *freq1){
for (int i=0;i<nfreq;i++) freq1[i]=0.0;
};

REALTYPE ProcessedStretch::get_stretch_multiplier(REALTYPE pos_percents){
REALTYPE result=1.0;
if (pars.stretch_multiplier.get_enabled()){
result*=pars.stretch_multiplier.get_value(pos_percents);
};
///REALTYPE transient=pars.get_transient(pos_percents);
///printf("\n%g\n",transient);
///REALTYPE threshold=0.05;
///REALTYPE power=1000.0;
///transient-=threshold;
///if (transient>0){
/// transient*=power*(1.0+power);
/// result/=(1.0+transient);
///};
///printf("tr=%g\n",result);
return result;
};

void ProcessedStretch::process_spectrum(REALTYPE *freq){
if (pars.harmonics.enabled) {
copy(freq,infreq);
do_harmonics(infreq,freq);
};

if (pars.freq_shift.enabled) {
copy(freq,infreq);
do_freq_shift(infreq,freq);
};
if (pars.pitch_shift.enabled) {
copy(freq,infreq);
do_pitch_shift(infreq,freq,pow(2.0,pars.pitch_shift.cents/1200.0));
};
if (pars.octave.enabled){
copy(freq,infreq);
do_octave(infreq,freq);
};


if (pars.spread.enabled){
copy(freq,infreq);
do_spread(infreq,freq);
};


if (pars.filter.enabled){
copy(freq,infreq);
do_filter(infreq,freq);
};
if (pars.free_filter.get_enabled()){
copy(freq,infreq);
do_free_filter(infreq,freq);
};

if (pars.compressor.enabled){
copy(freq,infreq);
do_compressor(infreq,freq);
};

};

//void ProcessedStretch::process_output(REALTYPE *smps,int nsmps){
//};


REALTYPE profile(REALTYPE fi, REALTYPE bwi){
REALTYPE x=fi/bwi;
x*=x;
if (x>14.71280603) return 0.0;
return exp(-x);///bwi;

};

void ProcessedStretch::do_harmonics(REALTYPE *freq1,REALTYPE *freq2){
REALTYPE freq=pars.harmonics.freq;
REALTYPE bandwidth=pars.harmonics.bandwidth;
int nharmonics=pars.harmonics.nharmonics;

if (freq<10.0) freq=10.0;

REALTYPE *amp=tmpfreq1;
for (int i=0;i<nfreq;i++) amp[i]=0.0;

for (int nh=1;nh<=nharmonics;nh++){//for each harmonic
REALTYPE bw_Hz;//bandwidth of the current harmonic measured in Hz
REALTYPE bwi;
REALTYPE fi;
REALTYPE f=nh*freq;

if (f>=samplerate/2) break;

bw_Hz=(pow(2.0,bandwidth/1200.0)-1.0)*f;
bwi=bw_Hz/(2.0*samplerate);
fi=f/samplerate;

REALTYPE sum=0.0;
REALTYPE max=0.0;
for (int i=1;i<nfreq;i++){//todo: optimize here
REALTYPE hprofile;
hprofile=profile((i/(REALTYPE)nfreq*0.5)-fi,bwi);
amp[i]+=hprofile;
if (max<hprofile) max=hprofile;
sum+=hprofile;
};
};

REALTYPE max=0.0;
for (int i=1;i<nfreq;i++){
if (amp[i]>max) max=amp[i];
};
if (max<1e-8) max=1e-8;

for (int i=1;i<nfreq;i++){
REALTYPE c,s;
REALTYPE a=amp[i]/max;
if (!pars.harmonics.gauss) a=(a<0.368?0.0:1.0);
freq2[i]=freq1[i]*a;
};

};


void ProcessedStretch::do_freq_shift(REALTYPE *freq1,REALTYPE *freq2){
zero(freq2);
int ifreq=(int)(pars.freq_shift.Hz/(samplerate*0.5)*nfreq);
for (int i=0;i<nfreq;i++){
int i2=ifreq+i;
if ((i2>0)&&(i2<nfreq)) freq2[i2]=freq1[i];
};
};
void ProcessedStretch::do_pitch_shift(REALTYPE *freq1,REALTYPE *freq2,REALTYPE rap){
zero(freq2);
if (rap<1.0){//down
for (int i=0;i<nfreq;i++){
int i2=(int)(i*rap);
if (i2>=nfreq) break;
freq2[i2]+=freq1[i];
};
};
if (rap>=1.0){//up
rap=1.0/rap;
for (int i=0;i<nfreq;i++){
freq2[i]=freq1[(int)(i*rap)];
};

};
};
void ProcessedStretch::do_octave(REALTYPE *freq1,REALTYPE *freq2){
zero(sumfreq);
if (pars.octave.om2>1e-3){
do_pitch_shift(freq1,tmpfreq1,0.25);
add(sumfreq,tmpfreq1,pars.octave.om2);
};
if (pars.octave.om1>1e-3){
do_pitch_shift(freq1,tmpfreq1,0.5);
add(sumfreq,tmpfreq1,pars.octave.om1);
};
if (pars.octave.o0>1e-3){
add(sumfreq,freq1,pars.octave.o0);
};
if (pars.octave.o1>1e-3){
do_pitch_shift(freq1,tmpfreq1,2.0);
add(sumfreq,tmpfreq1,pars.octave.o1);
};
if (pars.octave.o15>1e-3){
do_pitch_shift(freq1,tmpfreq1,3.0);
add(sumfreq,tmpfreq1,pars.octave.o15);
};
if (pars.octave.o2>1e-3){
do_pitch_shift(freq1,tmpfreq1,4.0);
add(sumfreq,tmpfreq1,pars.octave.o2);
};

REALTYPE sum=0.01+pars.octave.om2+pars.octave.om1+pars.octave.o0+pars.octave.o1+pars.octave.o15+pars.octave.o2;
if (sum<0.5) sum=0.5;
for (int i=0;i<nfreq;i++) freq2[i]=sumfreq[i]/sum;
};

void ProcessedStretch::do_filter(REALTYPE *freq1,REALTYPE *freq2){
REALTYPE low=0,high=0;
if (pars.filter.low<pars.filter.high){//sort the low/high freqs
low=pars.filter.low;
high=pars.filter.high;
}else{
high=pars.filter.low;
low=pars.filter.high;
};
int ilow=(int) (low/samplerate*nfreq*2.0);
int ihigh=(int) (high/samplerate*nfreq*2.0);
REALTYPE dmp=1.0;
REALTYPE dmprap=1.0-pow(pars.filter.hdamp*0.5,4.0);
for (int i=0;i<nfreq;i++){
REALTYPE a=0.0;
if ((i>=ilow)&&(i<ihigh)) a=1.0;
if (pars.filter.stop) a=1.0-a;
freq2[i]=freq1[i]*a*dmp;
dmp*=dmprap+1e-8;
};
};

void ProcessedStretch::update_free_filter(){
pars.free_filter.update_curve();
if (pars.free_filter.get_enabled()) {
for (int i=0;i<nfreq;i++){
REALTYPE freq=(REALTYPE)i/(REALTYPE) nfreq*samplerate*0.5;
free_filter_freqs[i]=pars.free_filter.get_value(freq);
};
}else{
for (int i=0;i<nfreq;i++){
free_filter_freqs[i]=1.0;
};
};
};
void ProcessedStretch::do_free_filter(REALTYPE *freq1,REALTYPE *freq2){
for (int i=0;i<nfreq;i++){
freq2[i]=freq1[i]*free_filter_freqs[i];
};
};

void ProcessedStretch::do_spread(REALTYPE *freq1,REALTYPE *freq2){
//convert to log spectrum
REALTYPE minfreq=20.0;
REALTYPE maxfreq=0.5*samplerate;

REALTYPE log_minfreq=log(minfreq);
REALTYPE log_maxfreq=log(maxfreq);
for (int i=0;i<nfreq;i++){
REALTYPE freqx=i/(REALTYPE) nfreq;
REALTYPE x=exp(log_minfreq+freqx*(log_maxfreq-log_minfreq))/maxfreq*nfreq;
REALTYPE y=0.0;
int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
REALTYPE xp=x-x0;
if (x<nfreq){
y=freq1[x0]*(1.0-xp)+freq1[x1]*xp;
};
tmpfreq1[i]=y;
};

//increase the bandwidth of each harmonic (by smoothing the log spectrum)
int n=2;
REALTYPE bandwidth=pars.spread.bandwidth;
REALTYPE a=1.0-pow(2.0,-bandwidth*bandwidth*10.0);
a=pow(a,8192.0/nfreq*n);

for (int k=0;k<n;k++){
tmpfreq1[0]=0.0;
for (int i=1;i<nfreq;i++){
tmpfreq1[i]=tmpfreq1[i-1]*a+tmpfreq1[i]*(1.0-a);
};
tmpfreq1[nfreq-1]=0.0;
for (int i=nfreq-2;i>0;i--){
tmpfreq1[i]=tmpfreq1[i+1]*a+tmpfreq1[i]*(1.0-a);
};
};

freq2[0]=0;
REALTYPE log_maxfreq_d_minfreq=log(maxfreq/minfreq);
for (int i=1;i<nfreq;i++){
REALTYPE freqx=i/(REALTYPE) nfreq;
REALTYPE x=log((freqx*maxfreq)/minfreq)/log_maxfreq_d_minfreq*nfreq;
REALTYPE y=0.0;
if ((x>0.0)&&(x<nfreq)){
int x0=(int)floor(x); if (x0>=nfreq) x0=nfreq-1;
int x1=x0+1; if (x1>=nfreq) x1=nfreq-1;
REALTYPE xp=x-x0;
y=tmpfreq1[x0]*(1.0-xp)+tmpfreq1[x1]*xp;
};
freq2[i]=y;
};


};


void ProcessedStretch::do_compressor(REALTYPE *freq1,REALTYPE *freq2){
REALTYPE rms=0.0;
for (int i=0;i<nfreq;i++) rms+=freq1[i]*freq1[i];
rms=sqrt(rms/nfreq)*0.1;
if (rms<1e-3) rms=1e-3;

REALTYPE rap=pow(rms,-pars.compressor.power);
for (int i=0;i<nfreq;i++) freq2[i]=freq1[i]*rap;
};



+ 166
- 0
ProcessedStretch.h View File

@@ -0,0 +1,166 @@
/*
Copyright (C) 2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/


#ifndef PROCESSED_STRETCH_H
#define PROCESSED_STRETCH_H

#include "FreeEdit.h"
#include "Stretch.h"
#include "XMLwrapper.h"


struct ProcessParameters{
ProcessParameters(){
pitch_shift.enabled=false;
pitch_shift.cents=0;

octave.enabled=false;
octave.om2=octave.om1=octave.o1=octave.o15=octave.o2=0;
octave.o0=1.0;

freq_shift.enabled=false;
freq_shift.Hz=0;

compressor.enabled=false;
compressor.power=0.0;

filter.enabled=false;
filter.stop=false;
filter.low=0.0;
filter.high=22000.0;
filter.hdamp=0.0;

harmonics.enabled=false;
harmonics.freq=440.0;
harmonics.bandwidth=25.0;
harmonics.nharmonics=10;
harmonics.gauss=false;

spread.enabled=false;
spread.bandwidth=0.3;
/// waveinfo.n_transients=1;
/// waveinfo.transients_data=new REALTYPE[1];
/// waveinfo.transients_data[0]=0;
};
~ProcessParameters(){
/// delete []waveinfo.transients_data;
};
void add2XML(XMLwrapper *xml);
void getfromXML(XMLwrapper *xml);
/// void set_transient_data(int n,REALTYPE *tr){
/// delete []waveinfo.transients_data;
/// waveinfo.n_transients=n;
/// waveinfo.transients_data=new REALTYPE[n];
/// for (int i=0;i<n;i++) waveinfo.transients_data[i]=tr[i];
/// };
///
/// REALTYPE get_transient(REALTYPE pos_percents){
/// REALTYPE pos=pos_percents*0.01;
/// if ((pos<0.0)||(pos>1.0)) return 0.0;
/// REALTYPE fpos=pos*waveinfo.n_transients;
/// int ipos=(int)fpos;
/// return waveinfo.transients_data[ipos];
/// };

struct{
bool enabled;
int cents;
}pitch_shift;

struct{
bool enabled;
REALTYPE om2,om1,o0,o1,o15,o2;
}octave;

struct{
bool enabled;
int Hz;
}freq_shift;

struct{
bool enabled;
REALTYPE power;
}compressor;

struct{
bool enabled;
REALTYPE low,high;
REALTYPE hdamp;
bool stop;
}filter;

struct{
bool enabled;
REALTYPE freq;
REALTYPE bandwidth;
int nharmonics;
bool gauss;
}harmonics;

struct{
bool enabled;
REALTYPE bandwidth;
}spread;
FreeEdit free_filter;
FreeEdit stretch_multiplier;

//the folowing parameter represents the information regarding the audio (it is not saved)
/// struct{
/// int n_transients;
/// REALTYPE *transients_data;
/// }waveinfo;
};

class ProcessedStretch:public Stretch{
public:
//stereo_mode: 0=mono,1=left,2=right
ProcessedStretch(REALTYPE rap_,int in_bufsize_,FFTWindow w=W_HAMMING,bool bypass_=false,REALTYPE samplerate_=44100,int stereo_mode=0);
~ProcessedStretch();
void set_parameters(ProcessParameters *ppar);
private:
REALTYPE get_stretch_multiplier(REALTYPE pos_percents);
// void process_output(REALTYPE *smps,int nsmps);
void process_spectrum(REALTYPE *freq);
void do_harmonics(REALTYPE *freq1,REALTYPE *freq2);
void do_pitch_shift(REALTYPE *freq1,REALTYPE *freq2,REALTYPE rap);
void do_freq_shift(REALTYPE *freq1,REALTYPE *freq2);
void do_octave(REALTYPE *freq1,REALTYPE *freq2);
void do_filter(REALTYPE *freq1,REALTYPE *freq2);
void do_free_filter(REALTYPE *freq1,REALTYPE *freq2);
void do_compressor(REALTYPE *freq1,REALTYPE *freq2);
void do_spread(REALTYPE *freq1,REALTYPE *freq2);

void copy(REALTYPE *freq1,REALTYPE *freq2);
void add(REALTYPE *freq2,REALTYPE *freq1,REALTYPE a=1.0);
void zero(REALTYPE *freq1);

void update_free_filter();
int nfreq;

REALTYPE *free_filter_freqs;
ProcessParameters pars;

REALTYPE *infreq,*sumfreq,*tmpfreq1,*tmpfreq2;
};

#endif



+ 305
- 0
Stretch.cpp View File

@@ -0,0 +1,305 @@
/*
Copyright (C) 2006-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include "Stretch.h"
#include <stdlib.h>
#include <math.h>

unsigned int FFT::start_rand_seed=1;

FFT::FFT(int nsamples_){
nsamples=nsamples_;
if (nsamples%2!=0) {
nsamples+=1;
printf("WARNING: Odd sample size on FFT::FFT() (%d)",nsamples);
};
smp=new REALTYPE[nsamples];for (int i=0;i<nsamples;i++) smp[i]=0.0;
freq=new REALTYPE[nsamples/2+1];for (int i=0;i<nsamples/2+1;i++) freq[i]=0.0;
window.data=new REALTYPE[nsamples];for (int i=0;i<nsamples;i++) window.data[i]=0.707;
window.type=W_RECTANGULAR;

#ifdef KISSFFT
datar=new kiss_fft_scalar[nsamples+2];
for (int i=0;i<nsamples+2;i++) datar[i]=0.0;
datac=new kiss_fft_cpx[nsamples/2+2];
for (int i=0;i<nsamples/2+2;i++) datac[i].r=datac[i].i=0.0;
plankfft = kiss_fftr_alloc(nsamples,0,0,0);
plankifft = kiss_fftr_alloc(nsamples,1,0,0);
#else
data=new REALTYPE[nsamples];for (int i=0;i<nsamples;i++) data[i]=0.0;
planfftw=fftwf_plan_r2r_1d(nsamples,data,data,FFTW_R2HC,FFTW_ESTIMATE);
planifftw=fftwf_plan_r2r_1d(nsamples,data,data,FFTW_HC2R,FFTW_ESTIMATE);
#endif
rand_seed=start_rand_seed;
start_rand_seed+=161103;
};

FFT::~FFT(){
delete []smp;
delete []freq;
delete []window.data;
#ifdef KISSFFT
delete []datar;
delete []datac;
free(plankfft);
free(plankifft);
#else
delete []data;
fftwf_destroy_plan(planfftw);
fftwf_destroy_plan(planifftw);
#endif
};

void FFT::smp2freq(){
#ifdef KISSFFT
for (int i=0;i<nsamples;i++) datar[i]=smp[i];
kiss_fftr(plankfft,datar,datac);
#else
for (int i=0;i<nsamples;i++) data[i]=smp[i];
fftwf_execute(planfftw);
#endif

for (int i=1;i<nsamples/2;i++) {
#ifdef KISSFFT
REALTYPE c=datac[i].r;
REALTYPE s=datac[i].i;
#else
REALTYPE c=data[i];
REALTYPE s=data[nsamples-i];
#endif
freq[i]=sqrt(c*c+s*s);
};
freq[0]=0.0;
};

void FFT::freq2smp(){
REALTYPE inv_2p15_2pi=1.0/16384.0*M_PI;
for (int i=1;i<nsamples/2;i++) {
rand_seed=(rand_seed*1103515245+12345);
unsigned int rand=(rand_seed>>16)&0x7fff;
REALTYPE phase=rand*inv_2p15_2pi;
#ifdef KISSFFT
datac[i].r=freq[i]*cos(phase);
datac[i].i=freq[i]*sin(phase);
#else
data[i]=freq[i]*cos(phase);
data[nsamples-i]=freq[i]*sin(phase);
#endif
};

#ifdef KISSFFT
datac[0].r=datac[0].i=0.0;
kiss_fftri(plankifft,datac,datar);
for (int i=0;i<nsamples;i++) smp[i]=datar[i]/nsamples;
#else
data[0]=data[nsamples/2+1]=data[nsamples/2]=0.0;
fftwf_execute(planifftw);
for (int i=0;i<nsamples;i++) smp[i]=data[i]/nsamples;
#endif
};

void FFT::applywindow(FFTWindow type){
if (window.type!=type){
window.type=type;
switch (type){
case W_RECTANGULAR:
for (int i=0;i<nsamples;i++) window.data[i]=0.707;
break;
case W_HAMMING:
for (int i=0;i<nsamples;i++) window.data[i]=0.53836-0.46164*cos(2*M_PI*i/(nsamples+1.0));
break;
case W_HANN:
for (int i=0;i<nsamples;i++) window.data[i]=0.5*(1.0-cos(2*M_PI*i/(nsamples-1.0)));
break;
case W_BLACKMAN:
for (int i=0;i<nsamples;i++) window.data[i]=0.42-0.5*cos(2*M_PI*i/(nsamples-1.0))+0.08*cos(4*M_PI*i/(nsamples-1.0));
break;
case W_BLACKMAN_HARRIS:
for (int i=0;i<nsamples;i++) window.data[i]=0.35875-0.48829*cos(2*M_PI*i/(nsamples-1.0))+0.14128*cos(4*M_PI*i/(nsamples-1.0))-0.01168*cos(6*M_PI*i/(nsamples-1.0));
break;

};
};
for (int i=0;i<nsamples;i++) smp[i]*=window.data[i];
};

/*******************************************/


Stretch::Stretch(REALTYPE rap_,int in_bufsize_,FFTWindow w,bool bypass_,REALTYPE samplerate_,int stereo_mode_){
samplerate=samplerate_;
rap=rap_;
in_bufsize=in_bufsize_;
bypass=bypass_;
stereo_mode=stereo_mode_;
if (rap>=1.0){//stretch
out_bufsize=in_bufsize;
}else{
//shorten
out_bufsize=(int)(in_bufsize*rap);
};
if (out_bufsize<8) out_bufsize=8;

if (bypass) out_bufsize=in_bufsize;

out_buf=new REALTYPE[out_bufsize];
old_out_smp_buf=new REALTYPE[out_bufsize*2];for (int i=0;i<out_bufsize*2;i++) old_out_smp_buf[i]=0.0;

poolsize=in_bufsize_*2;
in_pool=new REALTYPE[poolsize];for (int i=0;i<poolsize;i++) in_pool[i]=0.0;

infft=new FFT(poolsize);
outfft=new FFT(out_bufsize*2);
remained_samples=0.0;
window_type=w;
};

Stretch::~Stretch(){
delete [] out_buf;
delete [] old_out_smp_buf;
delete [] in_pool;
delete infft;
delete outfft;
};

void Stretch::set_rap(REALTYPE newrap){
if ((rap>=1.0)&&(newrap>=1.0)) rap=newrap;
};

void Stretch::process(REALTYPE *smps,int nsmps){
if (bypass){
for (int i=0;i<out_bufsize;i++) out_buf[i]=smps[i];
//post-process the output
// process_output(out_buf,out_bufsize);
return;
};
//add new samples to the pool
if ((smps!=NULL)&&(nsmps!=0)){
if (nsmps>poolsize){
printf("Warning nsmps> inbufsize on Stretch::process() %d>%d\n",nsmps,poolsize);
nsmps=poolsize;
};
int nleft=poolsize-nsmps;

//move left the samples from the pool to make room for new samples
for (int i=0;i<nleft;i++) in_pool[i]=in_pool[i+nsmps];

//add new samples to the pool
for (int i=0;i<nsmps;i++) in_pool[i+nleft]=smps[i];
};

//get the samples from the pool
for (int i=0;i<poolsize;i++) infft->smp[i]=in_pool[i];


infft->applywindow(window_type);
infft->smp2freq();


if (out_bufsize==in_bufsize){//output is the same as the input (as usual)
for (int i=0;i<in_bufsize;i++) outfft->freq[i]=infft->freq[i];
} else {
if (out_bufsize>in_bufsize){//output is longer
REALTYPE rap=(REALTYPE)in_bufsize/(REALTYPE)out_bufsize;
for (int i=0;i<out_bufsize;i++) {
REALTYPE pos=i*rap;
int poshi=(int)floor(pos);
REALTYPE poslo=pos-floor(pos);
outfft->freq[i]=infft->freq[poshi]*(1.0-poslo)+infft->freq[poshi+1]*poslo;
};
}else{//output is shorter
for (int i=0;i<out_bufsize;i++) outfft->freq[i]=0.0;
REALTYPE rap=(REALTYPE)out_bufsize/(REALTYPE)in_bufsize;
for (int i=0;i<in_bufsize;i++) {
REALTYPE pos=i*rap;
int poshi=(int)(floor(pos));
// #warning sa folosesc si poslo
outfft->freq[poshi]+=infft->freq[i];
};
};
};

process_spectrum(outfft->freq);

outfft->freq2smp();

//make the output buffer
REALTYPE tmp=1.0/(float) out_bufsize*M_PI;
REALTYPE hinv_sqrt2=0.853553390593;//(1.0+1.0/sqrt(2))*0.5;

REALTYPE ampfactor=1.0;
if (rap<1.0) ampfactor=rap*0.707;
else ampfactor=(out_bufsize/(float)poolsize)*4.0;

for (int i=0;i<out_bufsize;i++) {
REALTYPE a=(0.5+0.5*cos(i*tmp));
REALTYPE out=outfft->smp[i+out_bufsize]*(1.0-a)+old_out_smp_buf[i]*a;
out_buf[i]=out*(hinv_sqrt2-(1.0-hinv_sqrt2)*cos(i*2.0*tmp))*ampfactor;
};

//copy the current output buffer to old buffer
for (int i=0;i<out_bufsize*2;i++) old_out_smp_buf[i]=outfft->smp[i];

//post-process the output
//process_output(out_buf,out_bufsize);
};


int Stretch::get_nsamples(REALTYPE current_pos_percents){
if (bypass) return out_bufsize;
if (rap<1.0) return poolsize/2;//pentru shorten


long double used_rap=rap*get_stretch_multiplier(current_pos_percents);

long double r=out_bufsize/used_rap;
int ri=(int)floor(r);
long double rf=r-floor(r);

long double old_remained_samples_test=remained_samples;
remained_samples+=rf;
if (remained_samples>=1.0){
ri+=(int)floor(remained_samples);
remained_samples=remained_samples-floor(remained_samples);
};

long double rf_test=remained_samples-old_remained_samples_test;//this value should be almost like "rf" (for most of the time with the exception of changing the "ri" value) for extremely long stretches (otherwise the shown stretch value is not accurate)
//for stretch up to 10^18x "long double" must have at least 64 bits in the fraction part (true for gcc compiler on x86 and macosx)

// long double zzz=1.0;//quick test by adding a "largish" number and substracting it again
// rf_test+=zzz;
// rf_test-=zzz;

// printf("remained_samples=%.20Lg rf=%.20Lg rf_test=%.20Lg\n",remained_samples,rf,rf_test);
// printf("rf=%g rf_test=%g\n",(double)rf,(double)(rf_test));

if (ri>poolsize){
ri=poolsize;
};

return ri;
};

int Stretch::get_nsamples_for_fill(){
return poolsize;
};

REALTYPE Stretch::get_stretch_multiplier(REALTYPE pos_percents){
return 1.0;
};


+ 97
- 0
Stretch.h View File

@@ -0,0 +1,97 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef STRETCH_H
#define STRETCH_H
#include "globals.h"

#ifdef KISSFFT
#include <kiss_fftr.h>
#else
#include <fftw3.h>
#endif


enum FFTWindow{W_RECTANGULAR,W_HAMMING,W_HANN,W_BLACKMAN,W_BLACKMAN_HARRIS};

class FFT{//FFT class that considers phases as random
public:
FFT(int nsamples_);//samples must be even
~FFT();
void smp2freq();//input is smp, output is freq (phases are discarded)
void freq2smp();//input is freq,output is smp (phases are random)
void applywindow(FFTWindow type);
REALTYPE *smp;//size of samples/2
REALTYPE *freq;//size of samples
int nsamples;
private:
#ifdef KISSFFT
kiss_fftr_cfg plankfft,plankifft;
kiss_fft_scalar *datar;
kiss_fft_cpx *datac;
#else
fftwf_plan planfftw,planifftw;
REALTYPE *data;
#endif
struct{
REALTYPE *data;
FFTWindow type;
}window;

unsigned int rand_seed;
static unsigned int start_rand_seed;
};

class Stretch{
public:
Stretch(REALTYPE rap_,int in_bufsize_,FFTWindow w=W_HAMMING,bool bypass_=false,REALTYPE samplerate_=44100,int stereo_mode_=0);
//in_bufsize is also a half of a FFT buffer (in samples)
virtual ~Stretch();

void process(REALTYPE *smps,int nsmps);
// virtual void process_output(REALTYPE *smps,int nsmps){};

int in_bufsize;
int poolsize;//how many samples are inside the input_pool size (need to know how many samples to fill when seeking)

int out_bufsize;
REALTYPE *out_buf;//pot sa pun o variabila "max_out_bufsize" si asta sa fie marimea lui out_buf si pe out_bufsize sa il folosesc ca marime adaptiva

int get_nsamples(REALTYPE current_pos_percents);//how many samples are required to be added in the pool next time
int get_nsamples_for_fill();//how many samples are required to be added for a complete buffer refill (at start of the song or after seek)

void set_rap(REALTYPE newrap);//set the current stretch value

FFTWindow window_type;
protected:
virtual void process_spectrum(REALTYPE *freq){};
virtual REALTYPE get_stretch_multiplier(REALTYPE pos_percents);
REALTYPE samplerate;
int stereo_mode;//0=mono,1=left,2=right
private:
REALTYPE *in_pool;//de marimea in_bufsize
REALTYPE rap;
REALTYPE *old_out_smp_buf;

FFT *infft,*outfft;
long double remained_samples;//how many fraction of samples has remained (0..1)
bool bypass;
};


#endif


+ 71
- 0
Thread.cpp View File

@@ -0,0 +1,71 @@
/*
Copyright (C) 2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <unistd.h>
#include "Thread.h"
#include "globals.h"

#ifdef WINDOWS
DWORD WINAPI thread_function( LPVOID arg ) {
#else
void *thread_function(void *arg){
#endif
Thread *thr=(Thread *) arg;
thr->run();
thr->stopped=true;
thr->running=false;
return 0;
};

Thread::Thread(){
running=false;
stopnow=false;
stopped=false;
};

Thread::~Thread(){
stop();
};

bool Thread::start(){
if (running) return false;
#ifdef WINDOWS
hThread=CreateThread(NULL,0,thread_function,this,0,NULL);
#else
if (pthread_create(&thread,NULL,thread_function,this)!=0)return false;
#endif
running=true;
return true;
};

void Thread::stop(){
if (!running) return;
running=false;
stopped=false;
int maxwait=1000;
stopnow=true;
while(!stopped){
sleep(10);
};
};

bool Thread::is_running(){
return running;
};




+ 57
- 0
Thread.h View File

@@ -0,0 +1,57 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef THREAD_H
#define THREAD_H

#ifdef WINDOWS
#include <windows.h>
#include <winbase.h>
#else
#include <pthread.h>
#endif

class Thread{
public:
Thread();
~Thread();
bool start();
void stop();
bool is_running();
virtual void run()=0;
protected:
bool stopnow;//daca dau stop, atunci stop-now este true
private:
#ifdef WINDOWS
friend DWORD WINAPI thread_function( LPVOID arg );
#else
friend void *thread_function(void *arg);
#endif
bool running;
bool stopped;
#ifdef WINDOWS
HANDLE hThread;
#else
pthread_t thread;
#endif
};

#endif





+ 516
- 0
XMLwrapper.cpp View File

@@ -0,0 +1,516 @@
/*
XMLwrapper.C - XML wrapper
Copyright (C) 2003-2009 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include "XMLwrapper.h"
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>

//#include "Util.h"

int xml_k=0;
char tabs[STACKSIZE+2];

const char *XMLwrapper_whitespace_callback(mxml_node_t *node,int where){
const char *name=node->value.element.name;

if ((where==MXML_WS_BEFORE_OPEN)&&(!strcmp(name,"?xml"))) return(NULL);
if ((where==MXML_WS_BEFORE_CLOSE)&&(!strcmp(name,"string"))) return(NULL);

if ((where==MXML_WS_BEFORE_OPEN)||(where==MXML_WS_BEFORE_CLOSE)) {
/* const char *tmp=node->value.element.name;
if (tmp!=NULL) {
if ((strstr(tmp,"par")!=tmp)&&(strstr(tmp,"string")!=tmp)) {
printf("%s ",tmp);
if (where==MXML_WS_BEFORE_OPEN) xml_k++;
if (where==MXML_WS_BEFORE_CLOSE) xml_k--;
if (xml_k>=STACKSIZE) xml_k=STACKSIZE-1;
if (xml_k<0) xml_k=0;
printf("%d\n",xml_k);
printf("\n");
};
};
int i=0;
for (i=1;i<xml_k;i++) tabs[i]='\t';
tabs[0]='\n';tabs[i+1]='\0';
if (where==MXML_WS_BEFORE_OPEN) return(tabs);
else return("\n");
*/
return("\n");
};
return(0);
};


XMLwrapper::XMLwrapper(){
ZERO(&parentstack,(int)sizeof(parentstack));
ZERO(&values,(int)sizeof(values));

minimal=true;
stackpos=0;

tree=mxmlNewElement(MXML_NO_PARENT,"?xml version=\"1.0\" encoding=\"UTF-8\"?");
/* for mxml 2.1 (and older)
tree=mxmlNewElement(MXML_NO_PARENT,"?xml");
mxmlElementSetAttr(tree,"version","1.0");
mxmlElementSetAttr(tree,"encoding","UTF-8");
*/
mxml_node_t *doctype=mxmlNewElement(tree,"!DOCTYPE");
mxmlElementSetAttr(doctype,"paulstretch-data",NULL);

node=root=mxmlNewElement(tree,"paulstretch-data");
mxmlElementSetAttr(root,"version-major","1");
mxmlElementSetAttr(root,"version-minor","0");
mxmlElementSetAttr(root,"paulstretch-author","Nasca Octavian Paul");

//make the empty branch that will contain the information parameters
info=addparams0("INFORMATION");
//save specifications
beginbranch("BASE_PARAMETERS");
endbranch();

};

XMLwrapper::~XMLwrapper(){
if (tree!=NULL) mxmlDelete(tree);
};

bool XMLwrapper::checkfileinformation(char *filename){
stackpos=0;
ZERO(&parentstack,(int)sizeof(parentstack));

if (tree!=NULL) mxmlDelete(tree);tree=NULL;
char *xmldata=doloadfile(filename);
if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed


char *start=strstr(xmldata,"<INFORMATION>");
char *end=strstr(xmldata,"</INFORMATION>");

if ((start==NULL)||(end==NULL)||(start>end)) {
delete []xmldata;
return(false);
};
end+=strlen("</INFORMATION>");
end[0]='\0';
tree=mxmlNewElement(MXML_NO_PARENT,"?xml");
node=root=mxmlLoadString(tree,xmldata,MXML_OPAQUE_CALLBACK);
if (root==NULL) {
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
};

root=mxmlFindElement(tree,tree,"INFORMATION",NULL,NULL,MXML_DESCEND);
push(root);

if (root==NULL){
delete []xmldata;
mxmlDelete(tree);
node=root=tree=NULL;
return(false);
};

exitbranch();
if (tree!=NULL) mxmlDelete(tree);
delete []xmldata;
node=root=tree=NULL;

return(true);
};


/* SAVE XML members */

int XMLwrapper::saveXMLfile(const char *filename){
char *xmldata=getXMLdata();
if (xmldata==NULL) return(-2);

int compression=3;
int fnsize=strlen(filename)+100;
char *filenamenew=new char [fnsize];
snprintf(filenamenew,fnsize,"%s",filename);
int result=dosavefile(filenamenew,compression,xmldata);
delete []filenamenew;
delete []xmldata;
return(result);
};

char *XMLwrapper::getXMLdata(){
xml_k=0;
ZERO(tabs,STACKSIZE+2);
mxml_node_t *oldnode=node;
node=info;
//Info storing
node=oldnode;
char *xmldata=mxmlSaveAllocString(tree,XMLwrapper_whitespace_callback);

return(xmldata);
};


int XMLwrapper::dosavefile(char *filename,int compression,char *xmldata){
if (compression==0){
FILE *file;
file=fopen(filename,"w");
if (file==NULL) return(-1);
fputs(xmldata,file);
fclose(file);
} else {
if (compression>9) compression=9;
if (compression<1) compression=1;
char options[10];
snprintf(options,10,"wb%d",compression);

gzFile gzfile;
gzfile=gzopen(filename,options);
if (gzfile==NULL) return(-1);
gzputs(gzfile,xmldata);
gzclose(gzfile);
};
return(0);
};



void XMLwrapper::addpar(const char *name,int val){
addparams2("par","name",name,"value",int2str(val));
};

void XMLwrapper::addparreal(const char *name,REALTYPE val){
addparams2("par_real","name",name,"value",real2str(val));
};

void XMLwrapper::addparbool(const char *name,int val){
if (val!=0) addparams2("par_bool","name",name,"value","yes");
else addparams2("par_bool","name",name,"value","no");
};

void XMLwrapper::addparstr(const char *name,const char *val){
mxml_node_t *element=mxmlNewElement(node,"string");
mxmlElementSetAttr(element,"name",name);
mxmlNewText(element,0,val);
};


void XMLwrapper::beginbranch(const char *name){
push(node);
node=addparams0(name);
};

void XMLwrapper::beginbranch(const char *name,int id){
push(node);
node=addparams1(name,"id",int2str(id));
};

void XMLwrapper::endbranch(){
node=pop();
};



/* LOAD XML members */

int XMLwrapper::loadXMLfile(const char *filename){
if (tree!=NULL) mxmlDelete(tree);
tree=NULL;

ZERO(&parentstack,(int)sizeof(parentstack));
ZERO(&values,(int)sizeof(values));

stackpos=0;

char *xmldata=doloadfile(filename);
if (xmldata==NULL) return(-1);//the file could not be loaded or uncompressed
root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK);

delete []xmldata;

if (tree==NULL) return(-2);//this is not XML
node=root=mxmlFindElement(tree,tree,"paulstretch-data",NULL,NULL,MXML_DESCEND);
if (root==NULL) return(-3);//the XML doesnt embbed required data
push(root);

values.xml_version.major=str2int(mxmlElementGetAttr(root,"version-major"));
values.xml_version.minor=str2int(mxmlElementGetAttr(root,"version-minor"));

return(0);
};


char *XMLwrapper::doloadfile(const char *filename){
char *xmldata=NULL;
int filesize=-1;
//try get filesize as gzip data (first)
gzFile gzfile=gzopen(filename,"rb");
if (gzfile!=NULL){//this is a gzip file
// first check it's size
while(!gzeof(gzfile)) {
gzseek (gzfile,1024*1024,SEEK_CUR);
if (gztell(gzfile)>10000000) {
gzclose(gzfile);
goto notgzip;//the file is too big
};
};
filesize=gztell(gzfile);

//rewind the file and load the data
xmldata=new char[filesize+1];
ZERO(xmldata,filesize+1);

gzrewind(gzfile);
gzread(gzfile,xmldata,filesize);
gzclose(gzfile);
return (xmldata);
} else {//this is not a gzip file
notgzip:
FILE *file=fopen(filename,"rb");
if (file==NULL) return(NULL);
fseek(file,0,SEEK_END);
filesize=ftell(file);

xmldata=new char [filesize+1];
ZERO(xmldata,filesize+1);
rewind(file);
int tmp=fread(xmldata,filesize,1,file);
fclose(file);
return(xmldata);
};
};

bool XMLwrapper::putXMLdata(char *xmldata){
if (tree!=NULL) mxmlDelete(tree);
tree=NULL;

ZERO(&parentstack,(int)sizeof(parentstack));
ZERO(&values,(int)sizeof(values));

stackpos=0;

if (xmldata==NULL) return (false);
root=tree=mxmlLoadString(NULL,xmldata,MXML_OPAQUE_CALLBACK);

if (tree==NULL) return(false);
node=root=mxmlFindElement(tree,tree,"paulstretch-data",NULL,NULL,MXML_DESCEND);
if (root==NULL) return (false);;
push(root);

return(true);
};



int XMLwrapper::enterbranch(const char *name){
node=mxmlFindElement(peek(),peek(),name,NULL,NULL,MXML_DESCEND_FIRST);
if (node==NULL) return(0);

push(node);
return(1);
};

int XMLwrapper::enterbranch(const char *name,int id){
snprintf(tmpstr,TMPSTR_SIZE,"%d",id);
node=mxmlFindElement(peek(),peek(),name,"id",tmpstr,MXML_DESCEND_FIRST);
if (node==NULL) return(0);

push(node);
return(1);
};


void XMLwrapper::exitbranch(){
pop();
};


int XMLwrapper::getbranchid(int min, int max){
int id=str2int(mxmlElementGetAttr(node,"id"));
if ((min==0)&&(max==0)) return(id);
if (id<min) id=min;
else if (id>max) id=max;

return(id);
};

int XMLwrapper::getpar(const char *name,int defaultpar,int min,int max){
node=mxmlFindElement(peek(),peek(),"par","name",name,MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);

const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
int val=str2int(strval);
if (val<min) val=min;
else if (val>max) val=max;
return(val);
};

int XMLwrapper::getpar127(const char *name,int defaultpar){
return(getpar(name,defaultpar,0,127));
};

int XMLwrapper::getparbool(const char *name,int defaultpar){
node=mxmlFindElement(peek(),peek(),"par_bool","name",name,MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);

const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
if ((strval[0]=='Y')||(strval[0]=='y')) return(1);
else return(0);
};

void XMLwrapper::getparstr(const char *name,char *par,int maxstrlen){
ZERO(par,maxstrlen);
node=mxmlFindElement(peek(),peek(),"string","name",name,MXML_DESCEND_FIRST);
if (node==NULL) return;
if (node->child==NULL) return;
if (node->child->type!=MXML_OPAQUE) return;
snprintf(par,maxstrlen,"%s",node->child->value.element.name);
};

REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar){
node=mxmlFindElement(peek(),peek(),"par_real","name",name,MXML_DESCEND_FIRST);
if (node==NULL) return(defaultpar);

const char *strval=mxmlElementGetAttr(node,"value");
if (strval==NULL) return(defaultpar);
return(str2real(strval));
};

REALTYPE XMLwrapper::getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max){
REALTYPE result=getparreal(name,defaultpar);
if (result<min) result=min;
else if (result>max) result=max;
return(result);
};


/** Private members **/

char *XMLwrapper::int2str(int x){
snprintf(tmpstr,TMPSTR_SIZE,"%d",x);
return(tmpstr);
};

char *XMLwrapper::real2str(REALTYPE x){
snprintf(tmpstr,TMPSTR_SIZE,"%g",x);
return(tmpstr);
};

int XMLwrapper::str2int(const char *str){
if (str==NULL) return(0);
int result=strtol(str,NULL,10);
return(result);
};

REALTYPE XMLwrapper::str2real(const char *str){
if (str==NULL) return(0.0);
REALTYPE result=strtod(str,NULL);
return(result);
};


mxml_node_t *XMLwrapper::addparams0(const char *name){
mxml_node_t *element=mxmlNewElement(node,name);
return(element);
};

mxml_node_t *XMLwrapper::addparams1(const char *name,const char *par1,const char *val1){
mxml_node_t *element=mxmlNewElement(node,name);
mxmlElementSetAttr(element,par1,val1);
return(element);
};

mxml_node_t *XMLwrapper::addparams2(const char *name,const char *par1,const char *val1,const char *par2, const char *val2){
mxml_node_t *element=mxmlNewElement(node,name);
mxmlElementSetAttr(element,par1,val1);
mxmlElementSetAttr(element,par2,val2);
return(element);
};




void XMLwrapper::push(mxml_node_t *node){
if (stackpos>=STACKSIZE-1) {
printf("BUG!: XMLwrapper::push() - full parentstack\n");
return;
};
stackpos++;
parentstack[stackpos]=node;
// printf("push %d - %s\n",stackpos,node->value.element.name);
};
mxml_node_t *XMLwrapper::pop(){
if (stackpos<=0) {
printf("BUG!: XMLwrapper::pop() - empty parentstack\n");
return (root);
};
mxml_node_t *node=parentstack[stackpos];
parentstack[stackpos]=NULL;

// printf("pop %d - %s\n",stackpos,node->value.element.name);

stackpos--;
return(node);
};

mxml_node_t *XMLwrapper::peek(){
if (stackpos<=0) {
printf("BUG!: XMLwrapper::peek() - empty parentstack\n");
return (root);
};
return(parentstack[stackpos]);
};




+ 167
- 0
XMLwrapper.h View File

@@ -0,0 +1,167 @@
/*
XML.h - XML wrapper
Copyright (C) 2003-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2 or later) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <mxml.h>
#include "globals.h"

#ifndef XML_WRAPPER_H
#define XML_WRAPPER_H

#define TMPSTR_SIZE 50

//the maxim tree depth
#define STACKSIZE 100

class XMLwrapper{
public:
XMLwrapper();
~XMLwrapper();
/********************************/
/* SAVE to XML */
/********************************/

//returns 0 if ok or -1 if the file cannot be saved
int saveXMLfile(const char *filename);

//returns the new allocated string that contains the XML data (used for clipboard)
//the string is NULL terminated
char *getXMLdata();
//add simple parameter (name and value)
void addpar(const char *name,int val);
void addparreal(const char *name,REALTYPE val);
//add boolean parameter (name and boolean value)
//if the value is 0 => "yes", else "no"
void addparbool(const char *name,int val);

//add string parameter (name and string)
void addparstr(const char *name,const char *val);

//add a branch
void beginbranch(const char *name);
void beginbranch(const char *name, int id);

//this must be called after each branch (nodes that contains child nodes)
void endbranch();

/********************************/
/* LOAD from XML */
/********************************/
//returns 0 if ok or -1 if the file cannot be loaded
int loadXMLfile(const char *filename);

//used by the clipboard
bool putXMLdata(char *xmldata);
//enter into the branch
//returns 1 if is ok, or 0 otherwise
int enterbranch(const char *name);

//enter into the branch with id
//returns 1 if is ok, or 0 otherwise
int enterbranch(const char *name, int id);

//exits from a branch
void exitbranch();
//get the the branch_id and limits it between the min and max
//if min==max==0, it will not limit it
//if there isn't any id, will return min
//this must be called only imediately after enterbranch()
int getbranchid(int min, int max);

//it returns the parameter and limits it between min and max
//if min==max==0, it will not limit it
//if no parameter will be here, the defaultpar will be returned
int getpar(const char *name,int defaultpar,int min,int max);

//the same as getpar, but the limits are 0 and 127
int getpar127(const char *name,int defaultpar);
int getparbool(const char *name,int defaultpar);

void getparstr(const char *name,char *par,int maxstrlen);
REALTYPE getparreal(const char *name,REALTYPE defaultpar);
REALTYPE getparreal(const char *name,REALTYPE defaultpar,REALTYPE min,REALTYPE max);

bool minimal;//false if all parameters will be stored (used only for clipboard)
//opens a file and parse only the "information" data on it
//returns "true" if all went ok or "false" on errors
bool checkfileinformation(char *filename);
private:
int dosavefile(char *filename,int compression,char *xmldata);
char *doloadfile(const char *filename);

mxml_node_t *tree;//all xml data
mxml_node_t *root;//xml data used
mxml_node_t *node;//current node
mxml_node_t *info;//this node is used to store the information about the data
//adds params like this:
// <name>
//returns the node
mxml_node_t *addparams0(const char *name);

//adds params like this:
// <name par1="val1">
//returns the node
mxml_node_t *addparams1(const char *name,const char *par1,const char *val1);

//adds params like this:
// <name par1="val1" par2="val2">
//returns the node
mxml_node_t *addparams2(const char *name,const char *par1,const char *val1,const char *par2,const char *val2);
char *int2str(int x);
char *real2str(REALTYPE x);
int str2int(const char *str);
REALTYPE str2real(const char *str);
char tmpstr[TMPSTR_SIZE];
//this is used to store the parents
mxml_node_t *parentstack[STACKSIZE];
int stackpos;

void push(mxml_node_t *node);
mxml_node_t *pop();
mxml_node_t *peek();

//theese are used to store the values
struct{
struct {
int major,minor;
}xml_version;
}values;
};

#endif

+ 12
- 0
compile_linux_fftw.sh View File

@@ -0,0 +1,12 @@
outfile=paulstretch

rm -f $outfile

fluid -c GUI.fl
fluid -c FreeEditUI.fl

g++ -ggdb GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp `fltk-config --cflags` \
`fltk-config --ldflags` -laudiofile -lfftw3f -lvorbisenc -lvorbisfile -lportaudio -lpthread -lmad -lmxml -o $outfile

rm -f GUI.h GUI.cxx FreeEditUI.h FreeEditUI.cxx


+ 16
- 0
compile_linux_fftw_jack.sh View File

@@ -0,0 +1,16 @@
outfile=paulstretch

rm -f $outfile

fluid -c GUI.fl
fluid -c FreeEditUI.fl

g++ -ggdb GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp `fltk-config --cflags` \
`fltk-config --ldflags` \
-laudiofile -lfftw3f -lvorbisenc -lvorbisfile -lportaudio -lpthread -lmad -lmxml \
`pkg-config --cflags --libs jack samplerate` \
-DHAVE_JACK -DENABLE_RESAMPLING \
-o $outfile

rm -f GUI.h GUI.cxx FreeEditUI.h FreeEditUI.cxx


+ 11
- 0
compile_linux_kissfft.sh View File

@@ -0,0 +1,11 @@
outfile=paulstretch
rm -f $outfile

fluid -c GUI.fl
fluid -c FreeEditUI.fl


g++ -ggdb -DKISSFFT -I./contrib GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp contrib/*.c `fltk-config --cflags` \
`fltk-config --ldflags` -laudiofile -lvorbisenc -lvorbisfile -lportaudio -lpthread -lmad -lmxml -o $outfile

rm -f GUI.h GUI.cxx FreeEditUI.h FreeEditUI.cxx

+ 43
- 0
compile_win32.sh View File

@@ -0,0 +1,43 @@
outfile=paulstretch.exe

rm -f $outfile
wine /usr/local/i586-mingw32/bin/fluid.exe -c GUI.fl
wine /usr/local/i586-mingw32/bin/fluid.exe -c FreeEditUI.fl

clear

i586-mingw32msvc-g++ -O3 -DWINDOWS -DKISSFFT -I./contrib GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp contrib/*.c \
`/usr/local/i586-mingw32/bin/fltk-config --cflags` \
`/usr/local/i586-mingw32/bin/fltk-config --ldflags` \
/usr/local/i586-mingw32/lib/libvorbisenc.a \
/usr/local/i586-mingw32/lib/libvorbisfile.a \
/usr/local/i586-mingw32/lib/libvorbis.a \
/usr/local/i586-mingw32/lib/libogg.a \
/usr/local/i586-mingw32/lib/libportaudio.a \
/usr/local/i586-mingw32/lib/libaudiofile.a \
/usr/local/i586-mingw32/lib/libmad.a \
/usr/local/i586-mingw32/lib/libmxml.a \
/usr/local/i586-mingw32/lib/libz.a \
-lm -lwinmm -o $outfile

rm -f GUI.h GUI.cxx FreeEditUI.h FreeEditUI.cxx

strip $outfile

cat version.h | grep -v "#"

#compress the outfile (not necessary, but useful)
#upx $outfile














+ 11
- 0
contrib/COPYING_kiss_fft.txt View File

@@ -0,0 +1,11 @@
Copyright (c) 2003-2004 Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 150
- 0
contrib/_kiss_fft_guts.h View File

@@ -0,0 +1,150 @@
/*
Copyright (c) 2003-2004, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* kiss_fft.h
defines kiss_fft_scalar as either short or a float type
and defines
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
#include "kiss_fft.h"
#include <limits.h>

#define MAXFACTORS 32
/* e.g. an fft of length 128 has 4 factors
as far as kissfft is concerned
4*4*4*2
*/

struct kiss_fft_state{
int nfft;
int inverse;
int factors[2*MAXFACTORS];
kiss_fft_cpx twiddles[1];
};

/*
Explanation of macros dealing with complex math:

C_MUL(m,a,b) : m = a*b
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
C_SUB( res, a,b) : res = a - b
C_SUBFROM( res , a) : res -= a
C_ADDTO( res , a) : res += a
* */
#ifdef FIXED_POINT
#if (FIXED_POINT==32)
# define FRACBITS 31
# define SAMPPROD int64_t
#define SAMP_MAX 2147483647
#else
# define FRACBITS 15
# define SAMPPROD int32_t
#define SAMP_MAX 32767
#endif

#define SAMP_MIN -SAMP_MAX

#if defined(CHECK_OVERFLOW)
# define CHECK_OVERFLOW_OP(a,op,b) \
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); }
#endif


# define smul(a,b) ( (SAMPPROD)(a)*(b) )
# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )

# define S_MUL(a,b) sround( smul(a,b) )

# define C_MUL(m,a,b) \
do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)

# define DIVSCALAR(x,k) \
(x) = sround( smul( x, SAMP_MAX/k ) )

# define C_FIXDIV(c,div) \
do { DIVSCALAR( (c).r , div); \
DIVSCALAR( (c).i , div); }while (0)

# define C_MULBYSCALAR( c, s ) \
do{ (c).r = sround( smul( (c).r , s ) ) ;\
(c).i = sround( smul( (c).i , s ) ) ; }while(0)

#else /* not FIXED_POINT*/

# define S_MUL(a,b) ( (a)*(b) )
#define C_MUL(m,a,b) \
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
# define C_FIXDIV(c,div) /* NOOP */
# define C_MULBYSCALAR( c, s ) \
do{ (c).r *= (s);\
(c).i *= (s); }while(0)
#endif

#ifndef CHECK_OVERFLOW_OP
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
#endif

#define C_ADD( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
}while(0)
#define C_SUB( res, a,b)\
do { \
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
}while(0)
#define C_ADDTO( res , a)\
do { \
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
(res).r += (a).r; (res).i += (a).i;\
}while(0)

#define C_SUBFROM( res , a)\
do {\
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
(res).r -= (a).r; (res).i -= (a).i; \
}while(0)


#ifdef FIXED_POINT
# define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase))
# define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase))
# define HALF_OF(x) ((x)>>1)
#elif defined(USE_SIMD)
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
# define HALF_OF(x) ((x)*_mm_set1_ps(.5))
#else
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
# define HALF_OF(x) ((x)*.5)
#endif

#define kf_cexp(x,phase) \
do{ \
(x)->r = KISS_FFT_COS(phase);\
(x)->i = KISS_FFT_SIN(phase);\
}while(0)


/* a debugging function */
#define pcpx(c)\
fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )

+ 399
- 0
contrib/kiss_fft.c View File

@@ -0,0 +1,399 @@
/*
Copyright (c) 2003-2004, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#include "_kiss_fft_guts.h"
/* The guts header contains all the multiplication and addition macros that are defined for
fixed or floating point complex numbers. It also delares the kf_ internal functions.
*/

static kiss_fft_cpx *scratchbuf=NULL;
static size_t nscratchbuf=0;
static kiss_fft_cpx *tmpbuf=NULL;
static size_t ntmpbuf=0;

#define CHECKBUF(buf,nbuf,n) \
do { \
if ( nbuf < (size_t)(n) ) {\
free(buf); \
buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \
nbuf = (size_t)(n); \
} \
}while(0)


static void kf_bfly2(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx * Fout2;
kiss_fft_cpx * tw1 = st->twiddles;
kiss_fft_cpx t;
Fout2 = Fout + m;
do{
C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);

C_MUL (t, *Fout2 , *tw1);
tw1 += fstride;
C_SUB( *Fout2 , *Fout , t );
C_ADDTO( *Fout , t );
++Fout2;
++Fout;
}while (--m);
}

static void kf_bfly4(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
const size_t m
)
{
kiss_fft_cpx *tw1,*tw2,*tw3;
kiss_fft_cpx scratch[6];
size_t k=m;
const size_t m2=2*m;
const size_t m3=3*m;

tw3 = tw2 = tw1 = st->twiddles;

do {
C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);

C_MUL(scratch[0],Fout[m] , *tw1 );
C_MUL(scratch[1],Fout[m2] , *tw2 );
C_MUL(scratch[2],Fout[m3] , *tw3 );

C_SUB( scratch[5] , *Fout, scratch[1] );
C_ADDTO(*Fout, scratch[1]);
C_ADD( scratch[3] , scratch[0] , scratch[2] );
C_SUB( scratch[4] , scratch[0] , scratch[2] );
C_SUB( Fout[m2], *Fout, scratch[3] );
tw1 += fstride;
tw2 += fstride*2;
tw3 += fstride*3;
C_ADDTO( *Fout , scratch[3] );

if(st->inverse) {
Fout[m].r = scratch[5].r - scratch[4].i;
Fout[m].i = scratch[5].i + scratch[4].r;
Fout[m3].r = scratch[5].r + scratch[4].i;
Fout[m3].i = scratch[5].i - scratch[4].r;
}else{
Fout[m].r = scratch[5].r + scratch[4].i;
Fout[m].i = scratch[5].i - scratch[4].r;
Fout[m3].r = scratch[5].r - scratch[4].i;
Fout[m3].i = scratch[5].i + scratch[4].r;
}
++Fout;
}while(--k);
}

static void kf_bfly3(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
size_t m
)
{
size_t k=m;
const size_t m2 = 2*m;
kiss_fft_cpx *tw1,*tw2;
kiss_fft_cpx scratch[5];
kiss_fft_cpx epi3;
epi3 = st->twiddles[fstride*m];

tw1=tw2=st->twiddles;

do{
C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

C_MUL(scratch[1],Fout[m] , *tw1);
C_MUL(scratch[2],Fout[m2] , *tw2);

C_ADD(scratch[3],scratch[1],scratch[2]);
C_SUB(scratch[0],scratch[1],scratch[2]);
tw1 += fstride;
tw2 += fstride*2;

Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);

C_MULBYSCALAR( scratch[0] , epi3.i );

C_ADDTO(*Fout,scratch[3]);

Fout[m2].r = Fout[m].r + scratch[0].i;
Fout[m2].i = Fout[m].i - scratch[0].r;

Fout[m].r -= scratch[0].i;
Fout[m].i += scratch[0].r;

++Fout;
}while(--k);
}

static void kf_bfly5(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m
)
{
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
int u;
kiss_fft_cpx scratch[13];
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx *tw;
kiss_fft_cpx ya,yb;
ya = twiddles[fstride*m];
yb = twiddles[fstride*2*m];

Fout0=Fout;
Fout1=Fout0+m;
Fout2=Fout0+2*m;
Fout3=Fout0+3*m;
Fout4=Fout0+4*m;

tw=st->twiddles;
for ( u=0; u<m; ++u ) {
C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
scratch[0] = *Fout0;

C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

C_ADD( scratch[7],scratch[1],scratch[4]);
C_SUB( scratch[10],scratch[1],scratch[4]);
C_ADD( scratch[8],scratch[2],scratch[3]);
C_SUB( scratch[9],scratch[2],scratch[3]);

Fout0->r += scratch[7].r + scratch[8].r;
Fout0->i += scratch[7].i + scratch[8].i;

scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);

scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);

C_SUB(*Fout1,scratch[5],scratch[6]);
C_ADD(*Fout4,scratch[5],scratch[6]);

scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);

C_ADD(*Fout2,scratch[11],scratch[12]);
C_SUB(*Fout3,scratch[11],scratch[12]);

++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
}
}

/* perform the butterfly for one stage of a mixed radix FFT */
static void kf_bfly_generic(
kiss_fft_cpx * Fout,
const size_t fstride,
const kiss_fft_cfg st,
int m,
int p
)
{
int u,k,q1,q;
kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx t;
int Norig = st->nfft;

CHECKBUF(scratchbuf,nscratchbuf,p);

for ( u=0; u<m; ++u ) {
k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
scratchbuf[q1] = Fout[ k ];
C_FIXDIV(scratchbuf[q1],p);
k += m;
}

k=u;
for ( q1=0 ; q1<p ; ++q1 ) {
int twidx=0;
Fout[ k ] = scratchbuf[0];
for (q=1;q<p;++q ) {
twidx += fstride * k;
if (twidx>=Norig) twidx-=Norig;
C_MUL(t,scratchbuf[q] , twiddles[twidx] );
C_ADDTO( Fout[ k ] ,t);
}
k += m;
}
}
}

static
void kf_work(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
const size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st
)
{
kiss_fft_cpx * Fout_beg=Fout;
const int p=*factors++; /* the radix */
const int m=*factors++; /* stage's fft length/p */
const kiss_fft_cpx * Fout_end = Fout + p*m;

if (m==1) {
do{
*Fout = *f;
f += fstride*in_stride;
}while(++Fout != Fout_end );
}else{
do{
kf_work( Fout , f, fstride*p, in_stride, factors,st);
f += fstride*in_stride;
}while( (Fout += m) != Fout_end );
}

Fout=Fout_beg;

switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m); break;
case 3: kf_bfly3(Fout,fstride,st,m); break;
case 4: kf_bfly4(Fout,fstride,st,m); break;
case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
}
}

/* facbuf is populated by p1,m1,p2,m2, ...
where
p[i] * m[i] = m[i-1]
m0 = n */
static
void kf_factor(int n,int * facbuf)
{
int p=4;
double floor_sqrt;
floor_sqrt = floor( sqrt((double)n) );

/*factor out powers of 4, powers of 2, then any remaining primes */
do {
while (n % p) {
switch (p) {
case 4: p = 2; break;
case 2: p = 3; break;
default: p += 2; break;
}
if (p > floor_sqrt)
p = n; /* no more factors, skip to end */
}
n /= p;
*facbuf++ = p;
*facbuf++ = n;
} while (n > 1);
}

/*
*
* User-callable function to allocate all necessary storage space for the fft.
*
* The return value is a contiguous block of memory, allocated with malloc. As such,
* It can be freed with free(), rather than a kiss_fft-specific function.
* */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
{
kiss_fft_cfg st=NULL;
size_t memneeded = sizeof(struct kiss_fft_state)
+ sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/

if ( lenmem==NULL ) {
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
}else{
if (mem != NULL && *lenmem >= memneeded)
st = (kiss_fft_cfg)mem;
*lenmem = memneeded;
}
if (st) {
int i;
st->nfft=nfft;
st->inverse = inverse_fft;

for (i=0;i<nfft;++i) {
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
double phase = -2*pi*i / nfft;
if (st->inverse)
phase *= -1;
kf_cexp(st->twiddles+i, phase );
}

kf_factor(nfft,st->factors);
}
return st;
}



void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
if (fin == fout) {
CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
}else{
kf_work( fout, fin, 1,in_stride, st->factors,st );
}
}

void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
{
kiss_fft_stride(cfg,fin,fout,1);
}


/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the
buffers from CHECKBUF
*/
void kiss_fft_cleanup(void)
{
free(scratchbuf);
scratchbuf = NULL;
nscratchbuf=0;
free(tmpbuf);
tmpbuf=NULL;
ntmpbuf=0;
}

int kiss_fft_next_fast_size(int n)
{
while(1) {
int m=n;
while ( (m%2) == 0 ) m/=2;
while ( (m%3) == 0 ) m/=3;
while ( (m%5) == 0 ) m/=5;
if (m<=1)
break; /* n is completely factorable by twos, threes, and fives */
n++;
}
return n;
}

+ 119
- 0
contrib/kiss_fft.h View File

@@ -0,0 +1,119 @@
#ifndef KISS_FFT_H
#define KISS_FFT_H

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include <malloc.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
ATTENTION!
If you would like a :
-- a utility that will handle the caching of fft objects
-- real-only (no imaginary time component ) FFT
-- a multi-dimensional FFT
-- a command-line utility to perform ffts
-- a command-line utility to perform fast-convolution filtering

Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
in the tools/ directory.
*/

#ifdef USE_SIMD
# include <xmmintrin.h>
# define kiss_fft_scalar __m128
#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
#else
#define KISS_FFT_MALLOC malloc
#endif


#ifdef FIXED_POINT
#include <sys/types.h>
# if (FIXED_POINT == 32)
# define kiss_fft_scalar int32_t
# else
# define kiss_fft_scalar int16_t
# endif
#else
# ifndef kiss_fft_scalar
/* default is float */
# define kiss_fft_scalar float
# endif
#endif

typedef struct {
kiss_fft_scalar r;
kiss_fft_scalar i;
}kiss_fft_cpx;

typedef struct kiss_fft_state* kiss_fft_cfg;

/*
* kiss_fft_alloc
*
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
*
* typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
*
* The return value from fft_alloc is a cfg buffer used internally
* by the fft routine or NULL.
*
* If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
* The returned value should be free()d when done to avoid memory leaks.
*
* The state can be placed in a user supplied buffer 'mem':
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
* then the function places the cfg in mem and the size used in *lenmem
* and returns mem.
*
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
* then the function returns NULL and places the minimum cfg
* buffer size in *lenmem.
* */

kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);

/*
* kiss_fft(cfg,in_out_buf)
*
* Perform an FFT on a complex input buffer.
* for a forward FFT,
* fin should be f[0] , f[1] , ... ,f[nfft-1]
* fout will be F[0] , F[1] , ... ,F[nfft-1]
* Note that each element is complex and can be accessed like
f[k].r and f[k].i
* */
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);

/*
A more generic version of the above function. It reads its input from every Nth sample.
* */
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);

/* If kiss_fft_alloc allocated a buffer, it is one contiguous
buffer and can be simply free()d when no longer needed*/
#define kiss_fft_free free

/*
Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
your compiler output to call this before you exit.
*/
void kiss_fft_cleanup(void);

/*
* Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
*/
int kiss_fft_next_fast_size(int n);

#ifdef __cplusplus
}
#endif

#endif

+ 159
- 0
contrib/kiss_fftr.c View File

@@ -0,0 +1,159 @@
/*
Copyright (c) 2003-2004, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"

struct kiss_fftr_state{
kiss_fft_cfg substate;
kiss_fft_cpx * tmpbuf;
kiss_fft_cpx * super_twiddles;
#ifdef USE_SIMD
long pad;
#endif
};

kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
{
int i;
kiss_fftr_cfg st = NULL;
size_t subsize, memneeded;

if (nfft & 1) {
fprintf(stderr,"Real FFT optimization must be even.\n");
return NULL;
}
nfft >>= 1;

kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 2);

if (lenmem == NULL) {
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
} else {
if (*lenmem >= memneeded)
st = (kiss_fftr_cfg) mem;
*lenmem = memneeded;
}
if (!st)
return NULL;

st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
st->super_twiddles = st->tmpbuf + nfft;
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);

for (i = 0; i < nfft; ++i) {
double phase =
-3.14159265358979323846264338327 * ((double) i / nfft + .5);
if (inverse_fft)
phase *= -1;
kf_cexp (st->super_twiddles+i,phase);
}
return st;
}

void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
{
/* input buffer timedata is stored row-wise */
int k,ncfft;
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;

if ( st->substate->inverse) {
fprintf(stderr,"kiss fft usage error: improper alloc\n");
exit(1);
}

ncfft = st->substate->nfft;

/*perform the parallel fft of two real signals packed in real,imag*/
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
* contains the sum of the even-numbered elements of the input time sequence
* The imag part is the sum of the odd-numbered elements
*
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
* yielding DC of input time sequence
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
* yielding Nyquist bin of input time sequence
*/
tdc.r = st->tmpbuf[0].r;
tdc.i = st->tmpbuf[0].i;
C_FIXDIV(tdc,2);
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
freqdata[0].r = tdc.r + tdc.i;
freqdata[ncfft].r = tdc.r - tdc.i;
#ifdef USE_SIMD
freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
#else
freqdata[ncfft].i = freqdata[0].i = 0;
#endif

for ( k=1;k <= ncfft/2 ; ++k ) {
fpk = st->tmpbuf[k];
fpnk.r = st->tmpbuf[ncfft-k].r;
fpnk.i = - st->tmpbuf[ncfft-k].i;
C_FIXDIV(fpk,2);
C_FIXDIV(fpnk,2);

C_ADD( f1k, fpk , fpnk );
C_SUB( f2k, fpk , fpnk );
C_MUL( tw , f2k , st->super_twiddles[k]);

freqdata[k].r = HALF_OF(f1k.r + tw.r);
freqdata[k].i = HALF_OF(f1k.i + tw.i);
freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
}
}

void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
/* input buffer timedata is stored row-wise */
int k, ncfft;

if (st->substate->inverse == 0) {
fprintf (stderr, "kiss fft usage error: improper alloc\n");
exit (1);
}

ncfft = st->substate->nfft;

st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
C_FIXDIV(st->tmpbuf[0],2);

for (k = 1; k <= ncfft / 2; ++k) {
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
fk = freqdata[k];
fnkc.r = freqdata[ncfft - k].r;
fnkc.i = -freqdata[ncfft - k].i;
C_FIXDIV( fk , 2 );
C_FIXDIV( fnkc , 2 );

C_ADD (fek, fk, fnkc);
C_SUB (tmp, fk, fnkc);
C_MUL (fok, tmp, st->super_twiddles[k]);
C_ADD (st->tmpbuf[k], fek, fok);
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
#else
st->tmpbuf[ncfft - k].i *= -1;
#endif
}
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
}

+ 46
- 0
contrib/kiss_fftr.h View File

@@ -0,0 +1,46 @@
#ifndef KISS_FTR_H
#define KISS_FTR_H

#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif

/*
Real optimized version can save about 45% cpu time vs. complex fft of a real seq.

*/

typedef struct kiss_fftr_state *kiss_fftr_cfg;


kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
/*
nfft must be even

If you don't care to allocate space, use mem = lenmem = NULL
*/


void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
/*
input timedata has nfft scalar points
output freqdata has nfft/2+1 complex points
*/

void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
/*
input freqdata has nfft/2+1 complex points
output timedata has nfft scalar points
*/

#define kiss_fftr_free free

#ifdef __cplusplus
}
#endif
#endif

+ 35
- 0
globals.cpp View File

@@ -0,0 +1,35 @@
/*
Copyright (C) 2006 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "globals.h"
#ifdef WINDOWS
#include <windows.h>
#include <winbase.h>
#else
#include <unistd.h>
#endif

void sleep(int ms){
#ifdef WINDOWS
Sleep(1000);
#else
usleep(ms*1000);
#endif
};




+ 37
- 0
globals.h View File

@@ -0,0 +1,37 @@
/*
Copyright (C) 2006-2011 Nasca Octavian Paul
Author: Nasca Octavian Paul

This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.

You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef GLOBALS_H
#define GLOBALS_H

#define REALTYPE float

#ifndef NULL
#define NULL 0
#endif

void sleep(int ms);

#define ZERO(data,size) {char *data_=(char *) data;for (int i=0;i<size;i++) data_[i]=0;};

enum FILE_TYPE{
FILE_WAV,FILE_VORBIS,FILE_MP3
};


#endif


+ 81
- 0
readme.txt View File

@@ -0,0 +1,81 @@
PaulStretch
Copyright (C) 2006-2011 Nasca Octavian Paul, Tg. Mures, Romania

Released under GNU General Public License v.2 license

This is an experimental program for extreme stretching the audio.
Requirements:
- audiofile library
- libvorbis
- fltk library
- portaudio library
- libmad (for mp3 input)
- mxml library (for saving/loading parameters)
- not required, but you can use the FFTW library


This algorithm/program is suitable only for extreme stretching the audio.

There is lot room for improvements on this algorithm like:
- on sharp attacks to make the window smaller and larger on steady sounds. This avoid adding constant sidebands on steady sounds and smoothing too much the sharp sounds.
- even for small window, the sidebands produced can be lowered (how?)

Tips:
You can change the default output device with "PA_RECOMMENDED_OUTPUT_DEVICE" environment variable (used by PortAudio).
eg: set PA_RECOMMENDED_OUTPUT_DEVICE=1 #where 1 represents the index of the device; you can try other values for other devices

History:
20060527(0.0.1)
- First release

20060530(0.0.2)
- Ogg Vorbis output support
- Added a wxWidgets graphical user interface

20060812(1.000)
- Removed the wxWidgets GUI and added a FLTK GUI (because FLTK GUI is smaller)
- Added real-time processing/player
- Added input support for Ogg Vorbis files
- Improved the stretch algorithm and now the amount of stretch is unlimited (and on big stretch amounts, you don't need additional memory)
- Added "Freeze" button to the player
- It is possible to render to file only a selected part of the sound
- Other improvements

20060905(1.024)
- Added MP3 support for input
- Added bypass mode (if you click play with the right mouse button)
- Improved the precision of the position slider (now it shows really what's currenly playing)
- Added the possibility to set the stretch amount by entering the numeric value
- Added pause mode and volume control
- Added post-processing of the spectrum(pitch/frequency shift, octave mixer, compress,filter,harmonics)
- Command line parameter for input filename
- The file can be dragged from the explorer to the file text to open it

20090424(2.0)
- Added free envelopes, which allows the user to freely edit some parameters
- Added stretch multiplier (with free envelope) which make the stretching variable
- Added arbitrary frequency filter
- Added a frequency spreader effect, which increase the bandwith of each harmonic
- Added a frequency shifter which produces binaural beats (the beats frequencies are variable)
- Added 32 bit WAV rendering
- Other improvements and bugfixes
20110210(2.1)
- Added loading/saving parameters
- Added Linux Jack support (thanks to Robin Gareus for the patch)
- Added "Symmetric" mode of Binaural Beats
- Support for longer stretches - for the really patient ones - up to one quintillion times ( 10^18 x ) ;-)
- Fixed a bug which produced infinite loop at the end of some mp3 files (at playing or render)
- Fixed a bug in the mp3 reader
- other minor additions

20110211(2.1-0)
- Increased the precision of a paremeter for extreme long stretches

Enjoy! :)
Paul

zynaddsubfx_AT_yahoo com



+ 8
- 0
version.h View File

@@ -0,0 +1,8 @@
#ifndef VERSION_H
#define VERSION_H

#define VERSION "version 2.2 (20110210)"
//#define VERSION ""

#endif


Loading…
Cancel
Save