- commit
- 8f7f438335d24d8025431e777e5a3ba111ab896e
- parent
- 3c2970db2f559685f372facd7c89f752caf683e8
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2010-11-04 17:58
stretch and interpolation modes
Diffstat
| M | src/main.h | 1 | - |
| M | src/marker.cpp | 81 | +++++++++++++++++++++++++++++++++++++++++++------------------ |
| M | src/marker.h | 25 | ++++++++++++++++++++----- |
| M | src/playback.cpp | 7 | +------ |
| M | src/sample.cpp | 76 | +++++++++++++++++-------------------------------------------- |
| M | src/sample.h | 15 | ++++++++++++--- |
| M | xiRetimer | 0 |
7 files changed, 111 insertions, 94 deletions
diff --git a/src/main.h b/src/main.h
@@ -1,4 +1,3 @@1 -12 1 #ifndef __WXWIDGETSAPP_H 3 2 #define __WXWIDGETSAPP_H 4 3
diff --git a/src/marker.cpp b/src/marker.cpp
@@ -5,6 +5,7 @@ Marker::Marker() {
5 5 aold;
6 6 add(0,0);
7 7 add(1,1);
-1 8 interpolationMode=0;
8 9 }
9 10
10 11 Marker::~Marker() {
@@ -54,6 +55,9 @@ void Marker::setNew(int pi, float pnew) {
54 55 anew.set(resort(pi), pnew);
55 56 }
56 57
-1 58 int Marker::getInterpolationMode() {return interpolationMode;}
-1 59 void Marker::setInterpolationMode(int m) {interpolationMode=m;}
-1 60
57 61 float Marker::getRatio() {
58 62 if (getLength()>0)
59 63 return (getNew(getLength()-1)-getNew(0))/(getOld(getLength()-1)-getOld(0));
@@ -61,19 +65,30 @@ float Marker::getRatio() {
61 65 return NULL;
62 66 }
63 67
64 -1 /*
65 -1 float Marker::getRatio(int i) {
66 -1 if (i>=0 && i<getLength()-1)
67 -1 return (getNew(i+1)-getNew(i))/(getOld(i+1)-getOld(i));
68 -1 else
69 -1 return NULL;
70 -1 }
71 -1 */
72 -1
73 68 float Marker::getRatio(float o) {
74 -1 // TODO not exact at all
75 -1 float n=100;
76 -1 return ((old2new(o+1/n)-old2new(o-1/n))/(2/n));
-1 69 // derivate of old2new
-1 70 // hardcode the derivate to improve performance
-1 71 switch (getInterpolationMode()) {
-1 72 // linear
-1 73 case 0: {
-1 74 int i=getAreaOld(o);
-1 75 float dold=(getOld(i+1)-getOld(i));
-1 76 if (dold<=0) return 0;
-1 77 return (getNew(i+1)-getNew(i))/dold;
-1 78 } break;
-1 79 default: {
-1 80 // approxmiate ratio
-1 81 float n=100; // TODO automate this
-1 82 float o1=o-1/n;
-1 83 if (o1<0) o1=0;
-1 84 if (o1>1) return 0;
-1 85 float o2=o+1/n;
-1 86 if (o2<0) return 0;
-1 87 if (o2>1) o2=1;
-1 88 if (o2-o1<=0) return 0;
-1 89 return ((old2new(o2)-old2new(o1))/(o2-o1));
-1 90 }
-1 91 }
77 92 }
78 93
79 94 int Marker::getLength() {
@@ -109,24 +124,42 @@ int Marker::resort(int pi) {
109 124 }
110 125
111 126 float Marker::old2new(float o) {
112 -1 // !!linear
113 -1 // converts old 0-1 values to new 0-1 values
114 -1 int i=getAreaOld(o);
115 -1 // linear interpolation
116 -1 // n - n_i o - o_i
117 -1 // -------------- = --------------
118 -1 // n_{i+1} - n_i o_{i+1} - o_i
119 -1 return (o-getOld(i))/(getOld(i+1)-getOld(i))*(getNew(i+1)-getNew(i))+getNew(i);
-1 127 // this one does all the interpolation!
-1 128 // for performance reasons you should also hard code the interpolation modes to getRatio(float) and new2old
-1 129 switch (getInterpolationMode()) {
-1 130 // case 0: // linear is default
-1 131 default: {
-1 132 int i=getAreaOld(o);
-1 133 // linear interpolation
-1 134 // n - n_i o - o_i
-1 135 // -------------- = --------------
-1 136 // n_{i+1} - n_i o_{i+1} - o_i
-1 137 return (o-getOld(i))/(getOld(i+1)-getOld(i))*(getNew(i+1)-getNew(i))+getNew(i);
-1 138 }
-1 139 }
120 140 }
121 141
122 142 float Marker::new2old(float n) {
123 -1 // see old2new
124 -1 int i=getAreaNew(n);
125 -1 return (n-getNew(i))/(getNew(i+1)-getNew(i))*(getOld(i+1)-getOld(i))+getOld(i);
-1 143 // inverse of old2new
-1 144 // hardcode the derivate to improve performance
-1 145 switch (getInterpolationMode()) {
-1 146 // linear
-1 147 case 0: {
-1 148 int i=getAreaNew(n);
-1 149 return (n-getNew(i))/(getNew(i+1)-getNew(i))*(getOld(i+1)-getOld(i))+getOld(i);
-1 150 } break;
-1 151 default: {
-1 152 // approximate o;
-1 153 float o=n;
-1 154 for (int i=1; i<10; ++i) {
-1 155 o+=(n-old2new(o))/i;
-1 156 }
-1 157 return o;
-1 158 }
-1 159 }
126 160 }
127 161
128 162 float Marker::new2nnew(float n) {
129 -1 // normalizing
130 163 return (n-getNew(0))/(getNew(getLength()-1)-getNew(0));
131 164 }
132 165
diff --git a/src/marker.h b/src/marker.h
@@ -6,10 +6,23 @@ 6 6 7 7 /* 8 8 marker works with float values9 -1 it mapps old values from 0 (start) to 1 (end) to any new float values10 -1 nnew values are normalized new values-1 9 it mapps old values (o) from 0 (start) to 1 (end) to any new float values (n) -1 10 nnew values (nn) are normalized new values 11 11 most classes apart from marker use nnew values. Never forget to convert them! 12 12 */ -1 13 /* -1 14 For different modes of interpolation you have to edit 3 functions: -1 15 old2new -1 16 new2old - inverse of old2new -1 17 getRatio - derivate of old2new -1 18 // TODO define new2old and getRatio from old2new to make sure everything works together -1 19 */ -1 20 -1 21 /* -1 22 interpolation modes: -1 23 0 - LINEAR -1 24 // TODO define constants -1 25 */ 13 26 14 27 class Marker { 15 28 public: @@ -21,9 +34,6 @@ public: 21 34 float getNew(int pi); 22 35 float getOld(int pi); 23 36 void setNew(int pi, float pnew);24 -1 float getRatio(); // factor by wich the whole sample is stretched; used to guess the length of the output array;25 -1 // float getRatio(int i); // factor by wich this area is stretched;26 -1 float getRatio(float o); // factor by wich is stretched on this place;27 37 int getLength(); 28 38 void print(); 29 39 // 0-1 conversion @@ -33,10 +43,15 @@ public: 33 43 float nnew2new(float n); 34 44 int getAreaNew(float n); 35 45 int getAreaOld(float o); -1 46 float getRatio(); // factor by wich the whole sample is stretched; used to guess the length of the output array; -1 47 float getRatio(float o); // factor by wich is stretched on this place; -1 48 int getInterpolationMode(); -1 49 void setInterpolationMode(int m); 36 50 private: 37 51 Buffer anew; 38 52 Buffer aold; 39 53 int resort(int pi); -1 54 int interpolationMode; 40 55 }; 41 56 42 57 /*
diff --git a/src/playback.cpp b/src/playback.cpp
@@ -52,19 +52,14 @@ int Playback::play() {
52 52 }
53 53
54 54 int Playback::start() {
55 -1 // if ( sounds.dpos != sounds.dlen )
56 -1 // return 1;
57 -1
58 55 SDL_LockAudio();
59 -1
60 56 // if ( sounds.data ) {
61 57 // free(sounds.data);
62 58 // }
63 -1
64 59 int length=sample->getLength();
65 60 Uint8 idata[length];
66 61 for (int i=0; i<length; ++i) {
67 -1 idata[i]=int(sample->data[i]*128);
-1 62 idata[i]=int(sample->get(i/(float)length)*128);
68 63 }
69 64 std::cout << length << " ";
70 65 /* Put the sound data in the slot (it starts playing immediately) */
diff --git a/src/sample.cpp b/src/sample.cpp
@@ -1,6 +1,5 @@ 1 1 #include "sample.h"2 -13 -1 // TODO quality!!!-1 2 #include "rbprocess.h" 4 3 5 4 Sample::Sample(Marker* m) { 6 5 marker=m; @@ -8,6 +7,7 @@ Sample::Sample(Marker* m) { 8 7 data=new float[0]; 9 8 olength=0; 10 9 odata=new float[0]; -1 10 stretchMode=-1; 11 11 } 12 12 13 13 Sample::~Sample() { @@ -23,20 +23,22 @@ int Sample::getGuessedLength() { 23 23 } 24 24 25 25 float Sample::get(float nn) {26 -1 // TODO interpolation?27 -1 int i=int((getLength()-1)*nn);28 -1 if (i<0 || i>=getLength()) return NULL;-1 26 int i=int(length*nn); -1 27 if (i<0 || i>=length) return NULL; 29 28 return data[i]; 30 29 } 31 30 32 31 float Sample::getOld(float o) {33 -1 // TODO interpolation?34 32 int i=int((olength-1)*o); 35 33 if (i<0 || i>=olength) return NULL; 36 34 return odata[i]; 37 35 } 38 36 -1 37 int Sample::getStretchMode() {return stretchMode;} -1 38 void Sample::setStretchMode(int m) {stretchMode=m;} -1 39 39 40 int Sample::loadFile(const char* fileName) { -1 41 // TODO multi filetype support 40 42 SNDFILE *sndfile; 41 43 sfinfo; 42 44 // open file @@ -71,6 +73,7 @@ int Sample::loadFile(const char* fileName) { 71 73 } 72 74 73 75 int Sample::writeFile(const char* fileNameOut) { -1 76 // TODO multi filetype support 74 77 if (length<=0) { 75 78 std::cerr << "ERROR: Load a file first" << std::endl; 76 79 return 1; @@ -95,60 +98,23 @@ int Sample::writeFile(const char* fileNameOut) { 95 98 } 96 99 97 100 int Sample::process() {98 -1 //reads from odata and writes to data99 -1 const int bufferLength=4096; // important //100 -1 float **ibuf = new float *[1];101 -1 ibuf[0]=new float[bufferLength];102 -1 float **obuf = new float *[1];103 -1 int count2=0; // position in odata104 -1 int avail2=0; // position in data-1 101 /* -1 102 This function does the nmain thing: it stretches the original data as defined by the marker object. -1 103 Therefore it reads data from odata and writes to data. -1 104 */ 105 105 // setup data106 -1 length=olength*marker->getRatio();-1 106 length=int(marker->getRatio()*olength); 107 107 delete[] data; 108 108 data=new float[length];109 -1 for (int i=0; i<marker->getLength()-1; ++i) {110 -1 // float ratio=marker->getRatio(i); // redesign: getRatio(o)111 -1 int count=0; // position in section (o)112 -1 int frames=int((marker->getOld(i+1)-marker->getOld(i))*olength); // length of section (o)113 -1 while (count<frames && count2<olength && avail2<length) {114 -1 // load odata to ibuf115 -1 for (int j=0; j<bufferLength && count2+j<olength; ++j) {116 -1 ibuf[0][j]=odata[count2+j];117 -1 count++;-1 109 switch (getStretchMode()) { -1 110 // rubberband -1 111 case 0: RBprocess(odata, olength, data, length, marker); break; -1 112 default: { -1 113 for (int i=0; i<length; ++i) { -1 114 data[i]=getOld(marker->new2old(marker->nnew2new(i/(float)length))); 118 115 }119 -1 float ratio=marker->getRatio(count2/(float)olength);120 -1 count2+=bufferLength;121 -1 if (count2>olength) count2=olength;122 -1 // process ibuf123 -1 RubberBand::RubberBandStretcher ts(sfinfo.samplerate, 1, 0, ratio);124 -1 ts.setMaxProcessSize(bufferLength*10);125 -1 ts.study(ibuf, bufferLength, true);126 -1 int a1=-1;127 -1 int a2=0;128 -1 while (a1!=a2) {129 -1 ts.process(ibuf, ts.getSamplesRequired(), false);130 -1 a1=a2;131 -1 a2=ts.available();132 -1 }133 -1 ts.process(ibuf, bufferLength, true); // hope two times is enough134 -1 int avail=ts.available();135 -1136 -1 obuf[0]=new float[avail];137 -1 ts.retrieve(obuf, avail);138 -1 // write obuf to data139 -1 for (int j=0; j<avail && j+avail2<length; ++j) {140 -1 float value = obuf[0][j];141 -1 if (value > 1.f) value = 1.f;142 -1 if (value < -1.f) value = -1.f;143 -1 data[j+avail2] = value;144 -1 }145 -1 avail2+=avail;146 -1 delete[] obuf[0];147 116 } 148 117 }149 -1 delete[] ibuf[0];150 -1 delete[] ibuf;151 -1 delete[] obuf;152 -1 }153 118 -1 119 } 154 120
diff --git a/src/sample.h b/src/sample.h
@@ -4,26 +4,35 @@ 4 4 #include <sndfile.h> 5 5 #include <iostream> 6 6 #include "marker.h"7 -1 #include <rubberband/RubberBandStretcher.h>-1 7 -1 8 /* -1 9 Stretchmodes -1 10 0 - none (plain sample copy) -1 11 1 - rubberband -1 12 // TODO define constants -1 13 */ 8 14 9 15 class Sample { 10 16 public: 11 17 Sample(Marker* m); 12 18 ~Sample();13 -1 float *data;14 19 float get(float nn); // nnew 15 20 float getOld(float o); 16 21 int getLength(); 17 22 int getGuessedLength(); 18 23 int loadFile(const char* filename); 19 24 int writeFile(const char* filename);20 -1 int process();-1 25 int process(); // implements the main functionality 21 26 SF_INFO sfinfo; -1 27 int getStretchMode(); -1 28 void setStretchMode(int m); 22 29 private: -1 30 float *data; 23 31 int length; 24 32 Marker* marker; 25 33 int olength; 26 34 float *odata; -1 35 int stretchMode; 27 36 }; 28 37 29 38 /*