summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorStepan Moskovchenko <stevenm@rockbox.org>2005-04-19 15:57:07 +0000
committerStepan Moskovchenko <stevenm@rockbox.org>2005-04-19 15:57:07 +0000
commit1f5fb998192f512ac32dfa012586fb78a9a6a72c (patch)
treef95b3ccdd5f077f1870aea934d4b7d8d2fc64843 /apps
parentc3d0a229ccd859853641d7ee01e7c5c30045159c (diff)
downloadrockbox-1f5fb998192f512ac32dfa012586fb78a9a6a72c.tar.gz
rockbox-1f5fb998192f512ac32dfa012586fb78a9a6a72c.tar.bz2
rockbox-1f5fb998192f512ac32dfa012586fb78a9a6a72c.zip
Some shifting optimizations. Working code. 50% realtime.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6323 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/midi/guspat.c52
-rw-r--r--apps/plugins/midi/guspat.h1
-rw-r--r--apps/plugins/midi/midiutil.c132
-rw-r--r--apps/plugins/midi/sequencer.c31
-rw-r--r--apps/plugins/midi/synth.c158
-rw-r--r--apps/plugins/midi2wav.c65
6 files changed, 238 insertions, 201 deletions
diff --git a/apps/plugins/midi/guspat.c b/apps/plugins/midi/guspat.c
index f674b64caa..2172072eb1 100644
--- a/apps/plugins/midi/guspat.c
+++ b/apps/plugins/midi/guspat.c
@@ -66,18 +66,64 @@ struct GWaveform * loadWaveform(int file)
wav->res=readData(file, 36);
wav->data=readData(file, wav->wavSize);
+ wav->numSamples = wav->wavSize / 2;
int a=0;
+ return wav;
+ if(wav->mode & 1 == 0) //Whoops, 8 bit
+ {
+ wav->numSamples = wav->wavSize;
+
+ //Allocate a block for the rest of it
+ //It should end up right after the previous one.
+ wav->wavSize = wav->wavSize * 2;
+ void * foo = allocate(wav->wavSize);
+
+
+ for(a=0; a<1000; a++)
+ printf("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+
+ for(a=wav->wavSize-1; a>0; a-=2)
+ {
+
+ }
+ // int b1=wf->data[s]+((wf->mode & 2) << 6);
+ // return b1<<8;
+ }
+
+ /*
+//#if !defined(SIMULATOR)
+ for(a=0; a<wav->wavSize; a+=2)
+ {
+ unsigned char tmp;
+ tmp = wav->data[2*a];
+ wav->data[2*a] = wav->data[2*a+1];
+ wav->data[2*a+1] = tmp;
+ }
+//#endif
+
+ if(wav->mode & 2)
+ {
+ for(a=0; a<wav->wavSize/2; a++)
+ {
+ ((short *) wav->data)[a] = ((short *) wav->data)[a] - 32767;
+ }
+ }
+*/
+
+
+
//If we have a 16 bit waveform
- if(wav->mode & 1 && (wav->mode & 2))
+/* if(wav->mode & 1 && (wav->mode & 2))
{
for(a=0; a<wav->wavSize; a+=2) //Convert it to
{
- //wav->data[a]=wav->data[a]; //+((wav->mode & 2) << 6);
+ wav->data[a]=wav->data[a]+(1 << 7);
wav->data[a|1]=wav->data[(a)|1]+(1 << 7);
}
}
-
+*/
return wav;
}
diff --git a/apps/plugins/midi/guspat.h b/apps/plugins/midi/guspat.h
index 75bdb2ca01..6e41a85d23 100644
--- a/apps/plugins/midi/guspat.h
+++ b/apps/plugins/midi/guspat.h
@@ -36,6 +36,7 @@ struct GWaveform
unsigned char * name;
unsigned char fractions;
unsigned int wavSize;
+ unsigned int numSamples;
unsigned int startLoop;
unsigned int endLoop;
unsigned int sampRate;
diff --git a/apps/plugins/midi/midiutil.c b/apps/plugins/midi/midiutil.c
index 41a02ae682..bf25d1d277 100644
--- a/apps/plugins/midi/midiutil.c
+++ b/apps/plugins/midi/midiutil.c
@@ -63,33 +63,26 @@
extern struct plugin_api * rb;
+int chVol[16] IDATA_ATTR; //Channel volume
+int chPanLeft[16] IDATA_ATTR; //Channel panning
+int chPanRight[16] IDATA_ATTR;
+int chPat[16]; //Channel patch
+int chPW[16]; //Channel pitch wheel, MSB only
+
+
+/*
unsigned char chVol[16]; //Channel volume
unsigned char chPanLeft[16]; //Channel panning
unsigned char chPanRight[16];
unsigned char chPat[16]; //Channel patch
unsigned char chPW[16]; //Channel pitch wheel, MSB only
-
-
+*/
struct GPatch * gusload(char *);
struct GPatch * patchSet[128];
struct GPatch * drumSet[128];
-struct SynthObject voices[MAX_VOICES];
-
-struct SynthObject
-{
- int tmp;
- struct GWaveform * wf;
- unsigned int delta;
- unsigned int decay;
- unsigned int cp;
- unsigned char state, pstate, loopState, loopDir;
- unsigned char note, vol, ch, isUsed;
- int curRate, curOffset, targetOffset;
- int curPoint;
-};
-
+//char myarray[80] IDATA_ATTR;
struct Event
{
@@ -120,6 +113,34 @@ struct MIDIfile
unsigned char patches[128];
int numPatches;
};
+/*
+struct SynthObject
+{
+// int tmp;
+ struct GWaveform * wf;
+ unsigned int delta;
+ unsigned int decay;
+ unsigned int cp;
+ unsigned char state, loopState, loopDir;
+ unsigned char note, vol, ch, isUsed;
+ int curRate, curOffset, targetOffset;
+ unsigned int curPoint;
+};
+*/
+struct SynthObject
+{
+// int tmp;
+ struct GWaveform * wf;
+ int delta;
+ int decay;
+ int cp;
+ int state, loopState, loopDir;
+ int note, vol, ch, isUsed;
+ int curRate, curOffset, targetOffset;
+ int curPoint;
+};
+
+struct SynthObject voices[MAX_VOICES] IDATA_ATTR;
@@ -133,13 +154,16 @@ int readVarData(int file);
int midimain(void * filename);
-//Rick's code
void *alloc(int size)
{
static char *offset = NULL;
static int totalSize = 0;
char *ret;
+ int remainder = size % 4;
+
+ size = size + 4-remainder;
+
if (offset == NULL)
{
offset = rb->plugin_get_audio_buffer(&totalSize);
@@ -157,40 +181,34 @@ void *alloc(int size)
totalSize -= size + 4;
return ret;
}
+
+
+//Rick's code
/*
-void *ralloc(char *offset, int len)
+void *alloc(int size)
{
- int size;
+ static char *offset = NULL;
+ static int totalSize = 0;
char *ret;
+
if (offset == NULL)
{
- return alloc(len);
+ offset = rb->plugin_get_audio_buffer(&totalSize);
}
- size = *((unsigned int *)offset - 4);
-
- if (size >= 0x02000000)
+ if (size + 4 > totalSize)
{
return NULL;
}
- ret = alloc(len);
-
- if (len < size)
- {
- rb->memcpy(ret, offset, len);
- }
- else
- {
- rb->memcpy(ret, offset, size);
- rb->memset(ret, 0, len - size);
- }
+ ret = offset + 4;
+ *((unsigned int *)offset) = size;
+ offset += size + 4;
+ totalSize -= size + 4;
return ret;
-}
-*/
-
+}*/
void * allocate(int size)
{
return alloc(size);
@@ -222,44 +240,6 @@ int eof(int fd)
void printf(char *fmt, ...) {fmt=fmt; }
-/*
-void *audio_bufferbase;
-void *audio_bufferpointer;
-unsigned int audio_buffer_free;
-
-
-
-
-void *my_malloc(int size)
-{
-
- void *alloc;
-
- if (!audio_bufferbase)
- {
- audio_bufferbase = audio_bufferpointer
- = rb->plugin_get_audio_buffer(&audio_buffer_free);
-#if MEM <= 8 && !defined(SIMULATOR)
-
- if ((unsigned)(ovl_start_addr - (unsigned char *)audio_bufferbase)
- < audio_buffer_free)
- audio_buffer_free = ovl_start_addr - (unsigned char *)audio_bufferbase;
-#endif
- }
- if (size + 4 > audio_buffer_free)
- return 0;
- alloc = audio_bufferpointer;
- audio_bufferpointer += size + 4;
- audio_buffer_free -= size + 4;
- return alloc;
-}
-
-void setmallocpos(void *pointer)
-{
- audio_bufferpointer = pointer;
- audio_buffer_free = audio_bufferpointer - audio_bufferbase;
-}
-*/
void exit(int code)
{
code = code; //Stub function, kill warning for now
diff --git a/apps/plugins/midi/sequencer.c b/apps/plugins/midi/sequencer.c
index f7c6f30376..836866a5df 100644
--- a/apps/plugins/midi/sequencer.c
+++ b/apps/plugins/midi/sequencer.c
@@ -88,9 +88,30 @@ void setPW(int ch, int msb)
void pressNote(int ch, int note, int vol)
{
+/*
+ if(ch == 0) return;
+// if(ch == 1) return;
+ if(ch == 2) return;
+ if(ch == 3) return;
+ if(ch == 4) return;
+ if(ch == 5) return;
+ if(ch == 6) return;
+ if(ch == 7) return;
+ if(ch == 8) return;
+ if(ch == 9) return;
+ if(ch == 10) return;
+ if(ch == 11) return;
+ if(ch == 12) return;
+ if(ch == 13) return;
+ if(ch == 14) return;
+ if(ch == 15) return;
+*/
int a=0;
for(a=0; a<MAX_VOICES; a++)
{
+ if(voices[a].ch == ch && voices[a].note == note)
+ break;
+
if(voices[a].isUsed==0)
break;
}
@@ -107,7 +128,7 @@ void pressNote(int ch, int note, int vol)
voices[a].vol=vol;
voices[a].cp=0;
voices[a].state=STATE_ATTACK;
- voices[a].pstate=STATE_ATTACK;
+// voices[a].pstate=STATE_ATTACK;
voices[a].decay=255;
@@ -170,15 +191,12 @@ void releaseNote(int ch, int note)
{
if(voices[a].ch == ch && voices[a].note == note)
{
- //voices[a].isUsed=0;
if((voices[a].wf->mode & 28))
{
- voices[a].tmp=40;
+ // voices[a].tmp=40;
// voices[a].state = STATE_RELEASE; //Ramp down
// voices[a].state = STATE_RAMPDOWN; //Ramp down
-
-// voices[a].isUsed = 0;
setPoint(&voices[a], 3);
}
}
@@ -281,6 +299,9 @@ int tick(struct MIDIfile * mf)
{
tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]);
printf("\nMeta-Event: Tempo Set = %d", tempo);
+ bpm=mf->div*1000000/tempo;
+ numberOfSamples=SAMPLE_RATE/bpm;
+
}
}
tr->delta = 0;
diff --git a/apps/plugins/midi/synth.c b/apps/plugins/midi/synth.c
index 99864e557e..bafaf1c7ca 100644
--- a/apps/plugins/midi/synth.c
+++ b/apps/plugins/midi/synth.c
@@ -16,8 +16,6 @@
*
****************************************************************************/
-
-
extern struct plugin_api * rb;
struct Event * getEvent(struct Track * tr, int evNum)
@@ -178,7 +176,20 @@ int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
-inline signed short int getSample(struct GWaveform * wf, unsigned int s)
+int currentVoice IDATA_ATTR;
+struct SynthObject * so IDATA_ATTR;
+struct GWaveform * wf IDATA_ATTR;
+int s IDATA_ATTR;
+short s1 IDATA_ATTR;
+short s2 IDATA_ATTR;
+short sample IDATA_ATTR; //For synthSample
+unsigned int cpShifted IDATA_ATTR;
+
+unsigned char b1 IDATA_ATTR;
+unsigned char b2 IDATA_ATTR;
+
+
+inline int getSample(int s)
{
//16 bit samples
@@ -186,24 +197,23 @@ inline signed short int getSample(struct GWaveform * wf, unsigned int s)
{
if(s<<1 >= wf->wavSize)
+ {
+ printf("\n!!!!! %d \t %d", s<<1, wf->wavSize);
return 0;
-
-
- /*
- * Probably put the signed/unsigned and and 8-16 bit conversion
- * into the patch loader and have it run there, once.
- */
-
+ }
+// signed short a = ((short *)wf->data)[s];
//Sign conversion moved into guspat.c
- unsigned char b1=wf->data[s<<1]; //+((wf->mode & 2) << 6);
- unsigned char b2=wf->data[(s<<1)|1]; //+((wf->mode & 2) << 6);
+ b1=wf->data[s<<1]+((wf->mode & 2) << 6);
+ b2=wf->data[(s<<1)|1]+((wf->mode & 2) << 6);
return (b1 | (b2<<8)) ;
+
+ //Get rid of this sometime
}
else
{ //8-bit samples
//Do we even have anything 8-bit in our set?
- unsigned char b1=wf->data[s]+((wf->mode & 2) << 6);
+ int b1=wf->data[s]+((wf->mode & 2) << 6);
return b1<<8;
}
}
@@ -251,6 +261,12 @@ inline void setPoint(struct SynthObject * so, int pt)
*/
so->curRate = r<<10;
+ //Do this here because the patches assume a 44100 sampling rate
+ //We've halved our sampling rate, ergo the ADSR code will be
+ //called half the time. Ergo, double the rate to keep stuff
+ //sounding right.
+ so->curRate = so->curRate << 1;
+
so->targetOffset = so->wf->envOffset[pt]<<(20);
if(pt==0)
@@ -258,8 +274,6 @@ inline void setPoint(struct SynthObject * so, int pt)
}
-long msi=0;
-
inline void stopVoice(struct SynthObject * so)
{
if(so->state == STATE_RAMPDOWN)
@@ -269,51 +283,37 @@ inline void stopVoice(struct SynthObject * so)
}
-int rampDown = 0;
-inline signed short int synthVoice(int v)
+inline signed short int synthVoice()
{
- //Probably can combine these 2 lines into one..
- //But for now, this looks more readable
-// struct GPatch * pat = patchSet[chPat[voices[v].ch]];
-// struct GWaveform * wf = pat->waveforms[pat->noteTable[voices[v].note]];
- struct SynthObject * so = &voices[v];
- struct GWaveform * wf = so->wf;
+ so = &voices[currentVoice];
+ wf = so->wf;
- signed int s;
if(so->state != STATE_RAMPDOWN)
{
- if(so->loopDir==LOOPDIR_FORWARD)
- {
- so->cp += so->delta;
- }
- else
- {
- so->cp -= so->delta;
- }
+ so->cp += so->delta;
}
- if( (so->cp>>9 >= (wf->wavSize)) && (so->state != STATE_RAMPDOWN))
- stopVoice(so);
-
- /*
- //Original, working, no interpolation
- s=getSample(wf, (so->cp>>10));
- */
-
+ cpShifted = so->cp >> 10;
+ if( (cpShifted >= (wf->wavSize>>1)) && (so->state != STATE_RAMPDOWN))
+ stopVoice(so);
- int s2=getSample(wf, (so->cp>>10)+1);
+ s2 = getSample((cpShifted)+1);
- if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (so->cp>>10 <= (wf->startLoop>>1)))
+ if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop>>1)))
{
if(wf->mode & LOOP_REVERSE)
{
so->cp = (wf->endLoop)<<9;
- s2=getSample(wf, (so->cp>>10));
+ cpShifted = so->cp >> 10;
+ s2=getSample((cpShifted));
} else
+ {
+ so->delta = -so->delta;
so->loopDir = LOOPDIR_FORWARD;
+ }
}
if((wf->mode & 28) && (so->cp>>10 >= wf->endLoop>>1))
@@ -322,14 +322,21 @@ inline signed short int synthVoice(int v)
if((wf->mode & (24)) == 0)
{
so->cp = (wf->startLoop)<<9;
- s2=getSample(wf, (so->cp>>10));
+ cpShifted = so->cp >> 10;
+ s2=getSample((cpShifted));
} else
+ {
+ so->delta = -so->delta;
so->loopDir = LOOPDIR_REVERSE;
+ }
}
//Better, working, linear interpolation
- int s1=getSample(wf, (so->cp>>10));
- s = s1 + ((long)((s2 - s1) * (so->cp & 1023))>>10);
+ s1=getSample((cpShifted));
+ s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10);
+
+
+//ADSR COMMENT WOULD GO FROM HERE.........
if(so->curRate == 0)
stopVoice(so);
@@ -366,8 +373,9 @@ inline signed short int synthVoice(int v)
so->isUsed=0; //This is OK
- s = s * (so->curOffset >> 22);
- s = s>>6;
+ s = (s * (so->curOffset >> 22) >> 6);
+
+// ............. TO HERE
if(so->state == STATE_RAMPDOWN)
@@ -377,64 +385,28 @@ inline signed short int synthVoice(int v)
so->isUsed=0;
}
- s = s * so->decay; s = s >> 9;
+ s = s * so->decay; s = s >> 10;
return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14;
}
-
-int mhL[16];
-int mhR[16];
-int mp=0; //Mix position, for circular array
-// Was stuff for Ghetto Lowpass Filter, now deprecated.
-
-
inline void synthSample(int * mixL, int * mixR)
{
- int a=0;
- signed long int leftMix=0, rightMix=0, sample=0;
- for(a=0; a<MAX_VOICES; a++)
+// signed int leftMix=0, rightMix=0,
+ *mixL = 0;
+ *mixR = 0;
+ for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++)
{
- if(voices[a].isUsed==1)
+ if(voices[currentVoice].isUsed==1)
{
- sample = synthVoice(a);
-
- leftMix += (sample*chPanLeft[voices[a].ch])>>7;
- rightMix += (sample*chPanRight[voices[a].ch])>>7;
+ sample = synthVoice(currentVoice);
+ *mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7;
+ *mixR += (sample*chPanRight[voices[currentVoice].ch])>>7;
}
}
//TODO: Automatic Gain Control, anyone?
//Or, should this be implemented on the DSP's output volume instead?
- *mixL = leftMix;
- *mixR = rightMix;
-
return; //No more ghetto lowpass filter.. linear intrpolation works well.
-
-
- // HACK HACK HACK
- // This is the infamous Ghetto Lowpass Filter
- // Now that I have linear interpolation, it should not be needed anymore.
- /*
- mp++;
- if(mp==4)
- mp=0;
-
- mhL[mp]=leftMix;
- mhR[mp]=rightMix;
-
- *mixL = 0;
- *mixR = 0;
-
-
- for(a=0; a<4; a++)
- {
- *mixL += mhL[a];
- *mixR += mhR[a];
- }
- *mixL = *mixL>>4;
- *mixR = *mixR>>4;
- */
- // END HACK END HACK END HACK
}
diff --git a/apps/plugins/midi2wav.c b/apps/plugins/midi2wav.c
index 3cf2866a12..6dc7a626b5 100644
--- a/apps/plugins/midi2wav.c
+++ b/apps/plugins/midi2wav.c
@@ -16,7 +16,7 @@
*
****************************************************************************/
-#define SAMPLE_RATE 48000
+#define SAMPLE_RATE 22050
#define MAX_VOICES 100
@@ -37,6 +37,12 @@
#include "../../plugin.h"
+
+#include "lib/xxx2wav.h"
+
+int numberOfSamples IDATA_ATTR;
+long bpm;
+
#include "midi/midiutil.c"
#include "midi/guspat.h"
#include "midi/guspat.c"
@@ -46,7 +52,6 @@
-#include "lib/xxx2wav.h"
int fd=-1; //File descriptor where the output is written
@@ -58,6 +63,7 @@ struct plugin_api * rb;
+
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
TEST_PLUGIN_API(api);
@@ -80,6 +86,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
return PLUGIN_OK;
}
+signed char outputBuffer[3000] IDATA_ATTR; //signed char.. gonna run out of iram ... !
+
+
+int currentSample IDATA_ATTR;
+int outputBufferPosition IDATA_ATTR;
+int outputSampleOne IDATA_ATTR;
+int outputSampleTwo IDATA_ATTR;
+
int midimain(void * filename)
{
@@ -89,9 +103,6 @@ int midimain(void * filename)
rb->splash(HZ/5, true, "LOADING MIDI");
struct MIDIfile * mf = loadFile(filename);
- long bpm, nsmp, l;
-
- int bp=0;
rb->splash(HZ/5, true, "LOADING PATCHES");
if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1)
@@ -125,7 +136,7 @@ int midimain(void * filename)
samp=arg;
#else
file_info_struct file_info;
- file_info.samplerate = 48000;
+ file_info.samplerate = SAMPLE_RATE;
file_info.infile = fd;
file_info.channels = 2;
file_info.bitspersample = 16;
@@ -134,12 +145,11 @@ int midimain(void * filename)
#endif
- rb->splash(HZ/5, true, " START PLAYING ");
+ rb->splash(HZ/5, true, " Starting Playback ");
- signed char buf[3000];
// tick() will do one MIDI clock tick. Then, there's a loop here that
// will generate the right number of samples per MIDI tick. The whole
@@ -152,49 +162,56 @@ int midimain(void * filename)
printf("\nOkay, starting sequencing");
+
+ currentSample=0; //Sample counting variable
+ outputBufferPosition = 0;
+
+
+ bpm=mf->div*1000000/tempo;
+ numberOfSamples=SAMPLE_RATE/bpm;
+
+
+
//Tick() will return 0 if there are no more events left to play
while(tick(mf))
{
//Some annoying math to compute the number of samples
//to syntehsize per each MIDI tick.
- bpm=mf->div*1000000/tempo;
- nsmp=SAMPLE_RATE/bpm;
//Yes we need to do this math each time because the tempo
//could have changed.
// On second thought, this can be moved to the event that
//recalculates the tempo, to save a little bit of CPU time.
- for(l=0; l<nsmp; l++)
+ for(currentSample=0; currentSample<numberOfSamples; currentSample++)
{
- int s1, s2;
- synthSample(&s1, &s2);
+ synthSample(&outputSampleOne, &outputSampleTwo);
//16-bit audio because, well, it's better
// But really because ALSA's OSS emulation sounds extremely
//noisy and distorted when in 8-bit mode. I still do not know
//why this happens.
- buf[bp]=s1&0XFF; // Low byte first
- bp++;
- buf[bp]=s1>>8; //High byte second
- bp++;
+ outputBuffer[outputBufferPosition]=outputSampleOne&0XFF; // Low byte first
+ outputBufferPosition++;
+ outputBuffer[outputBufferPosition]=outputSampleOne>>8; //High byte second
+ outputBufferPosition++;
- buf[bp]=s2&0XFF; // Low byte first
- bp++;
- buf[bp]=s2>>8; //High byte second
- bp++;
+ outputBuffer[outputBufferPosition]=outputSampleTwo&0XFF; // Low byte first
+ outputBufferPosition++;
+ outputBuffer[outputBufferPosition]=outputSampleTwo>>8; //High byte second
+ outputBufferPosition++;
//As soon as we produce 2000 bytes of sound,
//write it to the sound card. Why 2000? I have
//no idea. It's 1 AM and I am dead tired.
- if(bp>=2000)
+ if(outputBufferPosition>=2000)
{
- rb->write(fd, buf, 2000);
- bp=0;
+ rb->write(fd, outputBuffer, 2000);
+ outputBufferPosition=0;
}
}
}