#include "setup.h"
#include "viewer.h"
#include <math.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <vdr/osd.h>
#include <vdr/thread.h>

extern int doexit;

ft_t fd_sound;
st_ssize_t test_read;
st_sample_t buffers[100][MAXWERTE * MAXCHANNELS];
cCondWait WaitFLUSH;
cCondWait WaitCALC;
cOsd *osd;
int width;
int height;
tColor color;
tColor background;
bool calc;
int activebuffer;
int usedbuffer;
int flushnumber;
int OLDK[MAXCHANNELS][SAMPLES];//alte Frequenzanteile

// --- cleanup -----------------------------------------------------------------

void cleanup(void) {
    isyslog("soundtest: extern \"C\" void cleanup()");
//    Close the input file and outputfile before exiting
    if (fd_sound) {
        st_close(fd_sound);
        free(fd_sound);
        fd_sound = NULL;
        }
}

// --- cViewerObject -----------------------------------------------------------

cViewerObject::cViewerObject(void) : cOsdObject(true) {
    isyslog("soundtest: cViewerObject::cViewerObject()");
/* : cThread("ViewerObject_ViewerObject::Action")*/
    color = Color = clrGreen;
    activebuffer = 0;
    fd_sound = NULL;
    samplerate = SoundtestSetup.samplerate;//
    size = SoundtestSetup.size;
    channels = SoundtestSetup.channels;//
    byteswap = (SoundtestSetup.byteswap == 0) ? true : false;
    if (channels > MAXCHANNELS) {
        channels = MAXCHANNELS;
        }
    if (channels < 1) {
        channels = 1;
        }
    st_signalinfo_t signalinfo = {samplerate, size, ST_ENCODING_UNSIGNED, channels, byteswap ? 0 : 1};
    fd_sound = st_open_read(SoundtestSetup.device, &signalinfo, SoundtestSetup.filetypeItems[SoundtestSetup.filetype]);
    if (fd_sound) {
	isyslog("soundtest: Samplerate:%d",fd_sound->info.rate);
	samplerate = fd_sound->info.rate;
	size = fd_sound->info.size;
	channels = fd_sound->info.channels;
	SoundtestSetup.returnsamplerate = samplerate;
	SoundtestSetup.returnsize = size;
	SoundtestSetup.returnchannels = channels;
	st_size_t buffer_size = MAXWERTE * channels;
	for (int i = 0; i < 100; i++) {
	    for (unsigned int j = 0; j < buffer_size; j++) {
		buffers[i][j] = 0;
		}
	    }
	update = new cUpdateData(buffer_size);
	calculate = new cCalculateData(samplerate, size, channels);
	}
}

cViewerObject::~cViewerObject() {
    isyslog("soundtest: cViewerObject::~cViewerObject()");
    if (calculate) {
	calculate->Pid++;
	}
    WaitCALC.Signal();
    if (update) {
	update->Pid++;
	}
    doexit++;
    Pid++;
    WaitFLUSH.Signal();
    Cancel(30);
}

void cViewerObject::Show(void) {
    isyslog("soundtest: cViewerObject::Show()");
    width = WIDTH;
    height = 512;
    background = SoundtestSetup.alpha << 24 | 0x00000000;
    osd = NULL;
    osd = cOsdProvider::NewOsd((720 - width) / 2, (576 - height) / 2);
    if (osd) {
	tArea Area = { 0, 0, width - 1, height - 1,  1 };
	osd->SetAreas(&Area, 1);
	osd->DrawRectangle(0, 0, width - 1, height - 1, background);
	osd->Flush();
    }
    Start();
}

eOSState cViewerObject::ProcessKey(eKeys Key) {
    eOSState state = cOsdObject::ProcessKey(Key);
    if (state == osUnknown) {
	switch (Key & ~k_Repeat) {
	    case k1:		SoundtestSetup.bars = 0;
				color_changed = true;
				break;
	    case k2:		SoundtestSetup.bars = 1;
				color_changed = true;
				break;
	    case k3:		SoundtestSetup.bars = 2;
				color_changed = true;
				break;
	    case k4:		SoundtestSetup.bars = 3;
				color_changed = true;
				break;
	    case k5:		SoundtestSetup.bars = 4;
				color_changed = true;
				break;
	    case k6:		SoundtestSetup.bars = 5;
				color_changed = true;
				break;
	    case kUp:		calculate->linear = !calculate->linear;
				break;
	    case kDown:		calculate->linear = !calculate->linear;
				break;
	    case kLeft:		calculate->screen--;
				if (calculate->screen < 0) {
				    calculate->screen = 1;
				    }
				color_changed = true;
				break;
	    case kRight:	calculate->screen++;
				if (calculate->screen > 1) {
				    calculate->screen = 0;
				    }
				color_changed = true;
				break;
	    case kRed:  	Color = clrRed;
			        color_changed = true;
				WaitFLUSH.Signal();
				break;
	    case kGreen:	Color = clrGreen;
			        color_changed = true;
			        WaitFLUSH.Signal();
				break;
	    case kYellow:	Color = clrYellow;
			        color_changed = true;
			        WaitFLUSH.Signal();
				break;
	    case kBlue: 	Color = clrBlue;
			        color_changed = true;
			        WaitFLUSH.Signal();
				break;
	    case kOk:   	color_changed = true;
    				WaitFLUSH.Signal();
				break;
	    case kBack:	        if (calculate) {
				    calculate->Pid++;
				    }
				WaitCALC.Signal();
			        if (update) {
				    update->Pid++;
				    }
				WaitFLUSH.Signal();
			        Pid++;
			        return osEnd;
	    case kNone: 	break;
	    default: 		return state;
	    }
        state = osContinue;
        }
    return state;
}

void cViewerObject::Action(void) {
    int pid = Pid = (int)getpid();
    isyslog("soundtest: cViewerObject::Action() - pid=%d", pid);
    flushnumber = -1;
    while((pid == Pid) || calc) {
	WaitFLUSH.Wait(0);
	if (osd && (pid == Pid)) {
	    if (usedbuffer != flushnumber) {
		if (color_changed) {
		    if (Color == color) {
    			osd->GetBitmap(0)->DrawRectangle(0, 0, width - 1, height - 1, background);
			}
		    else {
			color = Color;
    			osd->GetBitmap(0)->Reset();
			osd->GetBitmap(0)->SetColor(0, background);
			osd->GetBitmap(0)->SetColor(1, color);
    			osd->GetBitmap(0)->DrawRectangle(0, 0, width - 1, height - 1, background);
			}
		    for (int f = 0; f < MAXFREQUENCIES; f++) {
			for (int c = 0; c < channels; c++) {
			    OLDK[c][f] = 0;
			    }
	    		}
		    color_changed = false;
		    }
		osd->Flush();
#ifdef DEBUG
		isyslog("Flush(%d)", flushnumber);
#endif
	        flushnumber = usedbuffer;
	        WaitCALC.Signal();
	        }
	    }
	}
    if (osd) {
        osd->Flush();
	delete osd;
	osd = NULL;
	}
    isyslog("soundtest: cViewerObject::Action() end - pid=%d", pid);
}

// --- cCalculateData ----------------------------------------------------------

cCalculateData::cCalculateData(int samplerate, int samplesize, int samplechannels) : cThread("soundtest_CalculateData") {
    isyslog("soundtest: cCalculateData::cCalculateData(%d, %d)", samplerate, samplechannels);
    size = samplesize;
    channels = samplechannels;
    screen = SoundtestSetup.screen;
    linear = SoundtestSetup.linear;
    for (int i = 0; i < MAXWERTE; i++) {
	for (int c = 0; c < channels; c++) {
	    werte[0][i].x[c] = werte[1][i].x[c] = 128;
	    }
	}
    for (int f = 0; f < MAXFREQUENCIES; f++) {
	Q[f] = (f + 1) * (static_cast<long double>(samplerate)) / (static_cast<long double>(MAXWERTE)); //Festlegung der zu bestimmenden Frequenzen
	C[f] = cos((PI * 2 * Q[f]) / static_cast<long double>(samplerate));
	S[f] = sin((PI * 2 * Q[f]) / static_cast<long double>(samplerate));
        C[f] = cos((PI * 2 * Q[f]) / static_cast<long double>(samplerate));
	B[f] = 2 * C[f];
	for (int c = 0; c < channels; c++) {
    	    K[c][f] = 0;
	    OLDK[c][f] = 0;
	    }
	}
    first = true;
    Kanal1 = 0;
    if (channels > 1) {
	Kanal2 = 1;
	}
    else {
	Kanal2 = 0;
	}    
    Start();
}

cCalculateData::~cCalculateData() {
    isyslog("soundtest: cCalculateData::~cCalculateData()");
    Pid++;
    WaitCALC.Signal();
    calc = false;
    WaitFLUSH.Signal();
}

void cCalculateData::Calculate(void) {
    cBitmap *osdbmp = osd->GetBitmap(0);
//    isyslog("soundtest: cCalculateData::Calculate");
    int temp = activebuffer;
    if (temp == 0 || temp > 99) {
	usedbuffer = 99;
	}
    else {
	usedbuffer = temp - 1;
	}
#ifdef DEBUG
    isyslog("soundtest: Benutzter Puffer:%d", usedbuffer);
#endif
    int neu, alt;
    if (first) {
	neu = 0;
	alt = 1;
	}
    else {
	neu = 1;
	alt = 0;
	}
    first = !first;
    if (size == 1) {
	for (int i = 0; i < SAMPLES; i++) {
    	    for (int c = 0; c < channels; c++) {
		DD[c][i] = static_cast<long double>(buffers[usedbuffer][c + channels * i] >> 24);
		}
	    }
	}
    else {
	for (int i = 0; i < SAMPLES; i++) {
    	    for (int c = 0; c < channels; c++) {
		DD[c][i] = static_cast<long double>(buffers[usedbuffer][c + channels * i] >> 16);
		}
	    }	
	}
    if (!screen) {
	for (int i = 0; i < MAXWERTE; i++) {
    	    for (int c = 0; c < channels; c++) {
		D[neu][c][i] = static_cast<int>(buffers[usedbuffer][c + channels * i] >> 24);
		werte[neu][i].x[c] = static_cast<unsigned short int>(D[neu][c][i] + 128);
		}
	    }
	for (int i = 0; i < 256; i++) {
	    osdbmp->DrawPixel(i, 256 - werte[alt][i].x[Kanal1], background);
	    osdbmp->DrawPixel(i, 256 - werte[alt][256 + i].x[Kanal1], background);
	    osdbmp->DrawPixel(i, 256 - werte[neu][i].x[Kanal1], color);
	    osdbmp->DrawPixel(i, 256 - werte[neu][256 + i].x[Kanal1], color);
	    if (channels > 1) {
		osdbmp->DrawPixel(i, 512 - werte[alt][i].x[Kanal2], background);
		osdbmp->DrawPixel(i, 512 - werte[alt][256 + i].x[Kanal2], background);
		osdbmp->DrawPixel(i, 512 - werte[neu][i].x[Kanal2], color);
		osdbmp->DrawPixel(i, 512 - werte[neu][256 + i].x[Kanal2], color);
		osdbmp->DrawPixel(256 + 128 - D[alt][Kanal2][i], 128 + D[alt][Kanal1][i],  background);
		osdbmp->DrawPixel(256 + 128 - D[alt][Kanal2][256 + i], 128 + D[alt][Kanal1][256 + i],  background);
		osdbmp->DrawPixel(256 + 128 - D[neu][Kanal2][i], 128 + D[neu][Kanal1][i],  color);
		osdbmp->DrawPixel(256 + 128 - D[neu][Kanal2][256 + i], 128 + D[neu][Kanal1][256 + i],  color);
		}
	    }
	}
    if (size == 1) {
	for (int f = 0; f < MAXFREQUENCIES; f++) {
	    for (int c = 0; c < channels; c++) {
		U[c][SAMPLES - 1] = DD[c][SAMPLES - 1];
    		U[c][SAMPLES - 2] = DD[c][SAMPLES - 2] + B[f] * U[c][SAMPLES - 1];
    		for (int i = SAMPLES - 3; i >= 0; i--) {
		    U[c][i] = DD[c][i] + B[f] * U[c][i+1] - U[c][i+2];
		    }
		if (linear) {
		    K[c][f] = static_cast<int>(round(2 * sqrt((DD[c][0] + C[f] * U[c][0] - U[c][1]) * (DD[c][0] + C[f] * U[c][0] - U[c][1]) + (S[f] * U[c][0]) * (S[f] * U[c][0])) / SAMPLES));
		    }
		else {
		    long double tempdouble  = sqrt((DD[c][0] + C[f] * U[c][0] - U[c][1]) * (DD[c][0] + C[f] * U[c][0] - U[c][1]) + (S[f] * U[c][0]) * (S[f] * U[c][0])) / 256;
		    if (tempdouble < 1) {
		        K[c][f] = 1;
		        }
		    else {
		        K[c][f] = static_cast<int>(round(128 * log10(tempdouble) / log10(128)));
		        }
		    }
		}
	    }
	}
    else {
	for (int f = 0; f < MAXFREQUENCIES; f++) {
	    for (int c = 0; c < channels; c++) {
		U[c][SAMPLES - 1] = DD[c][SAMPLES - 1];
    		U[c][SAMPLES - 2] = DD[c][SAMPLES - 2] + B[f] * U[c][SAMPLES - 1];
    		for (int i = SAMPLES - 3; i >= 0; i--) {
		    U[c][i] = DD[c][i] + B[f] * U[c][i+1] - U[c][i+2];
		    }
		if (linear) {
		    K[c][f] = static_cast<int>(round(2 * sqrt((DD[c][0] + C[f] * U[c][0] - U[c][1]) * (DD[c][0] + C[f] * U[c][0] - U[c][1]) + (S[f] * U[c][0]) * (S[f] * U[c][0])) / (SAMPLES * 256)));
		    }
		else {
		    long double tempdouble = sqrt((DD[c][0] + C[f] * U[c][0] - U[c][1]) * (DD[c][0] + C[f] * U[c][0] - U[c][1]) + (S[f] * U[c][0]) * (S[f] * U[c][0])) / 65536;
		    if (tempdouble < 1) {
		        K[c][f] = 1;
		        }
		    else {
		        K[c][f] = static_cast<int>(round(128 * log10(tempdouble) / log10(128)));
		        }
		    }
		}
	    }
	}
    if (screen) {
	switch (SoundtestSetup.bars) {
	    case 0: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] > OLDK[Kanal1][f]) {
		    osdbmp->DrawRectangle(2 * f, 256 - K[Kanal1][f], 2 * f + 1,  256 - OLDK[Kanal1][f] - 1, color);
		    }
		else {
    		    if (K[Kanal1][f] < OLDK[Kanal1][f]) {
			osdbmp->DrawRectangle(2 * f, 256 - OLDK[Kanal1][f], 2 * f + 1,  256 - K[Kanal1][f] - 1, background);
			}
		    }
		OLDK[Kanal1][f] = K[Kanal1][f];
		if (channels > 1) {
    		    if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			osdbmp->DrawRectangle(2 * f, 512 - K[Kanal2][f], 2 * f + 1, 512 - OLDK[Kanal2][f] - 1, color);
			}
		    else {
    			if (K[Kanal2][f] < OLDK[Kanal2][f]) {
			    osdbmp->DrawRectangle(2 * f, 512 - OLDK[Kanal2][f], 2 * f + 1, 512 - K[Kanal2][f] - 1, background);
			    }
			}
			OLDK[Kanal2][f] = K[Kanal2][f];
			}
		    }
		break;
	    case 3: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
    		    if (K[Kanal1][f] > OLDK[Kanal1][f]) {
			osdbmp->DrawRectangle(2 * f, 256 - K[Kanal1][f], 2 * f + 1,  256 - OLDK[Kanal1][f] - 1, color);
			OLDK[Kanal1][f] = K[Kanal1][f];
			}
		    else {
    			if (OLDK[Kanal1][f] > 1) {
			    osdbmp->DrawRectangle(2 * f, 256 - OLDK[Kanal1][f], 2 * f + 1,  256 - OLDK[Kanal1][f], background);
			    OLDK[Kanal1][f]--;
			    }
			}
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
    			if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			    osdbmp->DrawRectangle(2 * f, 512 - K[Kanal2][f], 2 * f + 1, 512 - OLDK[Kanal2][f] - 1, color);
			    OLDK[Kanal2][f] = K[Kanal2][f];
			    }
			else {
    			    if (OLDK[Kanal2][f] > 1) {
				osdbmp->DrawRectangle(2 * f, 512 - OLDK[Kanal2][f], 2 * f + 1, 512 - OLDK[Kanal2][f], background);
				OLDK[Kanal2][f]--;
				}
			    }
			}
		    }
		}
		break;
	    case 1: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] > OLDK[Kanal1][f]) {
		    osdbmp->DrawRectangle(2 * f, 256 - K[Kanal1][f], 2 * f,  256 - OLDK[Kanal1][f] - 1, color);
		    }
		else {
    		    if (K[Kanal1][f] < OLDK[Kanal1][f]) {
		        osdbmp->DrawRectangle(2 * f, 256 - OLDK[Kanal1][f], 2 * f,  256 - K[Kanal1][f] - 1, background);
		        }
		    }
		OLDK[Kanal1][f] = K[Kanal1][f];
		if (channels > 1) {
    		    if (K[Kanal2][f] > OLDK[Kanal2][f]) {
		        osdbmp->DrawRectangle(2 * f, 512 - K[Kanal2][f], 2 * f, 512 - OLDK[Kanal2][f] - 1, color);
		        }
		    else {
    		        if (K[Kanal2][f] < OLDK[Kanal2][f]) {
			    osdbmp->DrawRectangle(2 * f, 512 - OLDK[Kanal2][f], 2 * f, 512 - K[Kanal2][f] - 1, background);
			    }
			}
		    OLDK[Kanal2][f] = K[Kanal2][f];
		    }
		}
		break;
	    case 4: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
    		    if (K[Kanal1][f] > OLDK[Kanal1][f]) {
			osdbmp->DrawRectangle(2 * f, 256 - K[Kanal1][f], 2 * f,  256 - OLDK[Kanal1][f] - 1, color);
			OLDK[Kanal1][f] = K[Kanal1][f];
			}
		    else {
    			if (OLDK[Kanal1][f] > 1) {
		    	    osdbmp->DrawRectangle(2 * f, 256 - OLDK[Kanal1][f], 2 * f,  256 - OLDK[Kanal1][f], background);
			    OLDK[Kanal1][f]--;
		    	    }
			}
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
    			if (K[Kanal2][f] > OLDK[Kanal2][f]) {
		    	    osdbmp->DrawRectangle(2 * f, 512 - K[Kanal2][f], 2 * f, 512 - OLDK[Kanal2][f] - 1, color);
			    OLDK[Kanal2][f] = K[Kanal2][f];
		    	    }
			else {
    		    	    if (OLDK[Kanal2][f] > 1) {
				osdbmp->DrawRectangle(2 * f, 512 - OLDK[Kanal2][f], 2 * f, 512 - OLDK[Kanal2][f], background);
				OLDK[Kanal2][f]--;
				}
			    }
			}
		    }
		}
		break;
	    case 2: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
		    osdbmp->DrawPixel(2 * f, 256 - OLDK[Kanal1][f], background);
		    osdbmp->DrawPixel(2 * f + 1, 256 - OLDK[Kanal1][f], background);
		    osdbmp->DrawPixel(2 * f, 256 - K[Kanal1][f], color);
		    osdbmp->DrawPixel(2 * f + 1, 256 - K[Kanal1][f], color);
		    OLDK[Kanal1][f] = K[Kanal1][f];
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
		        osdbmp->DrawPixel(2 * f, 512 - OLDK[Kanal2][f], background);
		        osdbmp->DrawPixel(2 * f + 1, 512 - OLDK[Kanal2][f], background);
		        osdbmp->DrawPixel(2 * f, 512 - K[Kanal2][f], color);
		        osdbmp->DrawPixel(2 * f + 1, 512 - K[Kanal2][f], color);
		        OLDK[Kanal2][f] = K[Kanal2][f];
			}
		    }
		}
	    case 5:
	    default: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
		    if (K[Kanal1][f] > OLDK[Kanal1][f]) {
			osdbmp->DrawPixel(2 * f, 256 - OLDK[Kanal1][f], background);
			osdbmp->DrawPixel(2 * f + 1, 256 - OLDK[Kanal1][f], background);
			osdbmp->DrawPixel(2 * f, 256 - K[Kanal1][f], color);
			osdbmp->DrawPixel(2 * f + 1, 256 - K[Kanal1][f], color);
			OLDK[Kanal1][f] = K[Kanal1][f];
			}
		    else {
			if (OLDK[Kanal1][f] > 1) {
			    osdbmp->DrawPixel(2 * f, 256 - OLDK[Kanal1][f], background);
			    osdbmp->DrawPixel(2 * f + 1, 256 - OLDK[Kanal1][f], background);
			    OLDK[Kanal1][f]--;
			    osdbmp->DrawPixel(2 * f, 256 - OLDK[Kanal1][f], color);
			    osdbmp->DrawPixel(2 * f + 1, 256 - OLDK[Kanal1][f], color);
			    }
			}
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
			if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			    osdbmp->DrawPixel(2 * f, 512 - OLDK[Kanal2][f], background);
			    osdbmp->DrawPixel(2 * f + 1, 512 - OLDK[Kanal2][f], background);
			    osdbmp->DrawPixel(2 * f, 512 - K[Kanal2][f], color);
			    osdbmp->DrawPixel(2 * f + 1, 512 - K[Kanal2][f], color);
			    OLDK[Kanal2][f] = K[Kanal2][f];
			    }
			else {
			    if (OLDK[Kanal2][f] > 1) {
				osdbmp->DrawPixel(2 * f, 512 - OLDK[Kanal2][f], background);
				osdbmp->DrawPixel(2 * f + 1, 512 - OLDK[Kanal2][f], background);
				OLDK[Kanal2][f]--;
				osdbmp->DrawPixel(2 * f, 512 - OLDK[Kanal2][f], color);
				osdbmp->DrawPixel(2 * f + 1, 512 - OLDK[Kanal2][f], color);
				}
			    }
			}
		    }
		}
	    }
	}
    else {
	switch (SoundtestSetup.bars) {
	    case 0:
	    case 1: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] > OLDK[Kanal1][f]) {
		    osdbmp->DrawRectangle(256 + f,  255 + 128 - K[Kanal1][f], 256 + f,  255 + 128 - OLDK[Kanal1][f] - 1, color);
		    }
		else {
    		    if (K[Kanal1][f] < OLDK[Kanal1][f]) {
			osdbmp->DrawRectangle(256 + f,  255 + 128 - OLDK[Kanal1][f], 256 + f,  255 + 128 - K[Kanal1][f] - 1, background);
			}
		    }
		OLDK[Kanal1][f] = K[Kanal1][f];
		if (channels > 1) {
    		    if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			osdbmp->DrawRectangle(256 + f, 511 - K[Kanal2][f], 256 + f, 511 - OLDK[Kanal2][f] - 1, color);
			}
		    else {
    			if (K[Kanal2][f] < OLDK[Kanal2][f]) {
			    osdbmp->DrawRectangle(256 + f, 511 - OLDK[Kanal2][f], 256 + f, 511 - K[Kanal2][f] - 1, background);
			    }
			}
		    OLDK[Kanal2][f] = K[Kanal2][f];
		    }
		}
		break;
	    case 3:
	    case 4: for (int f = 0; f < MAXFREQUENCIES; f++) {
		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
    		    if (K[Kanal1][f] > OLDK[Kanal1][f]) {
			osdbmp->DrawRectangle(256 + f,  255 + 128 - K[Kanal1][f], 256 + f,  255 + 128 - OLDK[Kanal1][f] - 1, color);
			OLDK[Kanal1][f] = K[Kanal1][f];
			}
		    else {
			if (OLDK[Kanal1][f] > 1) {
			    osdbmp->DrawRectangle(256 + f,  255 + 128 - OLDK[Kanal1][f], 256 + f,  255 + 128 - OLDK[Kanal1][f], background);
			    OLDK[Kanal1][f]--;
			    }
			}
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
    			if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			    osdbmp->DrawRectangle(256 + f, 511 - K[Kanal2][f], 256 + f, 511 - OLDK[Kanal2][f] - 1, color);
			    OLDK[Kanal2][f] = K[Kanal2][f];
			    }
			else {
    			    if (OLDK[Kanal2][f] > 1) {
				osdbmp->DrawRectangle(256 + f, 511 - OLDK[Kanal2][f], 256 + f, 511 - OLDK[Kanal2][f], background);
				OLDK[Kanal2][f]--;
				}
			    }
			}
		    }
		}
		break;
	    case 2: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
		    osdbmp->DrawPixel(256 + f,  255 + 128 - OLDK[Kanal1][f], background);
		    osdbmp->DrawPixel(256 + f,  255 + 128 - K[Kanal1][f], color);
		    OLDK[Kanal1][f] = K[Kanal1][f];
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
			osdbmp->DrawPixel(256 + f, 511 - K[Kanal2][f], color);
			osdbmp->DrawPixel(256 + f, 511 - OLDK[Kanal2][f], background);
			OLDK[Kanal2][f] = K[Kanal2][f];
			}
		    }
		}
		break;
	    case 5:
	    default: for (int f = 0; f < MAXFREQUENCIES; f++) {
    		if (K[Kanal1][f] != OLDK[Kanal1][f]) {
		    if (K[Kanal1][f] > OLDK[Kanal1][f]) {
			osdbmp->DrawPixel(256 + f,  255 + 128 - OLDK[Kanal1][f], background);
			osdbmp->DrawPixel(256 + f,  255 + 128 - K[Kanal1][f], color);
			OLDK[Kanal1][f] = K[Kanal1][f];
			}
		    else {
			if (OLDK[Kanal1][f] > 1) {
			    osdbmp->DrawPixel(256 + f,  255 + 128 - OLDK[Kanal1][f], background);
			    OLDK[Kanal1][f]--;
			    osdbmp->DrawPixel(256 + f,  255 + 128 - OLDK[Kanal1][f], color);
			    }
			}
		    }
		if (channels > 1) {
    		    if (K[Kanal2][f] != OLDK[Kanal2][f]) {
			if (K[Kanal2][f] > OLDK[Kanal2][f]) {
			    osdbmp->DrawPixel(256 + f,  511 - OLDK[Kanal2][f], background);
			    osdbmp->DrawPixel(256 + f,  511 - K[Kanal2][f], color);
			    OLDK[Kanal2][f] = K[Kanal2][f];
			    }
			else {
			    if (OLDK[Kanal2][f] > 1) {
				osdbmp->DrawPixel(256 + f,  511 - OLDK[Kanal2][f], background);
				OLDK[Kanal2][f]--;
				osdbmp->DrawPixel(256 + f,  511 - OLDK[Kanal2][f], color);
				}
			    }
			}
		    }
		}
	    }
	}
}

void cCalculateData::Action(void) {
    int pid = Pid = (int)getpid();
    isyslog("soundtest: cCalculateData::Action() end - pid=%d", pid);
    int oldactivebuffer = -1;
    int oldflush = -1;
    calc = true;
    WaitFLUSH.Signal();
    while (pid == Pid) {
	if (osd && fd_sound) {
	    if (oldactivebuffer != activebuffer) {
		oldactivebuffer = activebuffer;
		if (oldflush != flushnumber) {
		    oldflush = flushnumber;
		    Calculate();
		    WaitFLUSH.Signal();
		    }
		else {
		    WaitCALC.Wait(0);
		    }
		}
	    else {
		WaitCALC.Wait(0);
		}
	    }
	}
    calc = false;
    WaitFLUSH.Signal();
    isyslog("soundtest: cCalculateData::Action() end - pid=%d", pid);
}

// --- cUpdateData -------------------------------------------------------------

cUpdateData::cUpdateData(st_size_t buffersize) : cThread("soundtest_UpdateData") {
    isyslog("soundtest: cUpdateData::cUpdateData(%d)", buffersize);
    buffer_size = buffersize;
    Start();
}

cUpdateData::~cUpdateData() {
    isyslog("soundtest: cUpdateData::~cUpdateData()");
    Pid++;    
    WaitCALC.Signal();
}

void cUpdateData::Action(void) {
    int pid = Pid = (int)getpid();
    isyslog("soundtest: cUpdateData::Action() - pid=%d", pid);
    int oldexit = doexit;
    if (fd_sound) {
	WaitCALC.Signal();
	while ((pid == Pid) && (oldexit == doexit)) {
	    test_read = st_read(fd_sound, buffers[activebuffer], buffer_size);
#ifdef DEBUG
	    isyslog("soundtest: aktiver Puffer:%d: %d", activebuffer, test_read);
#endif
	    activebuffer++;
	    if (activebuffer > 99) {
	        activebuffer = 0;
	        }
	    WaitCALC.Signal();
	    }
	}
    WaitCALC.Signal();
    if (fd_sound) {
        st_close(fd_sound);
        free(fd_sound);
	fd_sound = NULL;
	}
    isyslog("soundtest: cUpdateData::Action() end - pid=%d", pid);
}
