Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

SoundUI.cc

Go to the documentation of this file.
00001 /*
00002 
00003     Sound user interface
00004     Copyright (C) 2000-2003 Jussi Laako
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 */
00021 
00022 
00023 #include <pthread.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028 #include <math.h>
00029 #include <float.h>
00030 #include <signal.h>
00031 #include <errno.h>
00032 #include <sched.h>
00033 #include <sys/types.h>
00034 #include <sys/mman.h>
00035 #include <gtk/gtk.h>
00036 
00037 #include "SoundUI.hh"
00038 
00039 
00040 static const char *cpWindowTxt = "Sound UI";
00041 static const char *cpChannelPfx = "Channel";
00042 // Table 1
00043 static const char *cpLServerTxt = "Server";
00044 static const char *cpLChannelTxt = "Channel";
00045 static const char *cpBConnectTxt = "Connect";
00046 // -
00047 static const char *cpLInputLevelTxt = "Average peak input level";
00048 static const char *cpLEqTxt = "Eq";
00049 // Eq
00050 static const char *cpLOutputLevelTxt = "Level";
00051 static const char *cpBApplyCurveTxt = "Apply curve";
00052 
00053 clSoundUI *SoundUI;
00054 
00055 
00056 int main (int argc, char *argv[])
00057 {
00058     int iRetVal;
00059 
00060     signal(SIGPIPE, SIG_IGN);
00061     signal(SIGFPE, SIG_IGN);
00062     SoundUI = new clSoundUI(&argc, &argv);
00063     iRetVal = SoundUI->Exec();
00064     delete SoundUI;
00065     return iRetVal;
00066 }
00067 
00068 
00069 // Wrapper functions
00070 
00071 
00072 gboolean WrapOnDeleteEvent (GtkWidget *gwSender, GdkEvent *geEvent,
00073     gpointer gpData)
00074 {
00075     return SoundUI->OnDeleteEvent(gwSender, geEvent, gpData);
00076 }
00077 
00078 
00079 void WrapOnClickedEvent (GtkButton *gbButton, gpointer gpData)
00080 {
00081     SoundUI->OnClickedEvent(gbButton, gpData);
00082 }
00083 
00084 
00085 gint WrapOnTimeoutEvent (gpointer gpData)
00086 {
00087     return SoundUI->OnTimeoutEvent(gpData);
00088 }
00089 
00090 
00091 void WrapOnToggledEvent (GtkToggleButton *gtbToggleButton, gpointer gpData)
00092 {
00093     SoundUI->OnToggledEvent(gtbToggleButton, gpData);
00094 }
00095 
00096 
00097 void WrapOnValueChangedEvent (GtkAdjustment *gaAdjustment, gpointer gpData)
00098 {
00099     SoundUI->OnValueChangedEvent(gaAdjustment, gpData);
00100 }
00101 
00102 
00103 void WrapOnApplyCurveClicked (GtkButton *gbButton, gpointer gpData)
00104 {
00105     SoundUI->OnApplyCurveClicked(gbButton, gpData);
00106 }
00107 
00108 
00109 void WrapOnMotionCurve (GtkWidget *gwSender, GdkEventMotion *gemEvent,
00110     gpointer gpData)
00111 {
00112     SoundUI->OnMotionCurve(gwSender, gemEvent, gpData);
00113 }
00114 
00115 
00116 void *WrapSoundOutThread (void *vpData)
00117 {
00118     return SoundUI->SoundOutThread(vpData);
00119 }
00120 
00121 
00122 void *WrapSoundInThread (void *vpData)
00123 {
00124     return SoundUI->SoundInThread(vpData);
00125 }
00126 
00127 
00128 // clSoundUI
00129 
00130 
00131 void clSoundUI::GetCfg ()
00132 {
00133     int iALSA;
00134     int iLocalCh;
00135     int iLocalSR;
00136     long lLocalSC;
00137 
00138     Cfg.SetFileName(SUI_CFGFILE);
00139     if (!Cfg.GetStr("Device", cpDevice))
00140         strcpy(cpDevice, SUI_DEF_DEVICE);
00141     if (!Cfg.GetInt("DeviceBase", &iDeviceBase))
00142         iDeviceBase = -1;
00143     if (Cfg.GetInt("UseALSA", &iALSA))
00144     {
00145         bALSA = (iALSA) ? true : false;
00146     }
00147     else bALSA = false;
00148     if (!Cfg.GetInt("ALSACard", &iALSACard))
00149         iALSACard = 0;
00150     if (!Cfg.GetInt("ALSADevice", &iALSADevice))
00151         iALSADevice = 0;
00152     if (!Cfg.GetInt("ALSASubDevice", &iALSASubDevice))
00153         iALSASubDevice = 0;
00154     if (Cfg.GetInt("Channels", &iLocalCh))
00155         iChCount = iLocalCh;
00156     else
00157         iChCount = SUI_DEF_CHANNELS;
00158     if (Cfg.GetInt("SampleRate", &iLocalSR))
00159         iSampleRate = iLocalSR;
00160     else
00161         iSampleRate = SUI_DEF_SAMPLERATE;
00162     if (Cfg.GetInt("SampleCount", &lLocalSC))
00163         lSampleCount = lLocalSC;
00164     else
00165         lSampleCount = SUI_SAMPLECOUNT;
00166     if (!Cfg.GetInt("UpdateInterval", &iVuTimeout))
00167         iVuTimeout = SUI_VU_TIMEOUT;
00168     if (!Cfg.GetInt("DCBlock", &iDCBlock))
00169         iDCBlock = 0;
00170 }
00171 
00172 
00173 void clSoundUI::BuildGUI ()
00174 {
00175     int iWidgetCntr;
00176     int iWidgetCount;
00177     int iLocalOctaves;
00178     long lSpectSize;
00179 
00180     gwWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00181     gtk_window_set_title(GTK_WINDOW(gwWindow), cpWindowTxt);
00182     // allow_shrink, allow_grow, auto_shrink
00183     gtk_window_set_policy(GTK_WINDOW(gwWindow), TRUE, TRUE, FALSE);
00184     gtk_container_set_border_width(GTK_CONTAINER(gwWindow), SUI_PADDING);
00185 
00186     // homogenous, spacing
00187     gwVBox = gtk_vbox_new(FALSE, SUI_PADDING);
00188     gtk_container_add(GTK_CONTAINER(gwWindow), gwVBox);
00189     gtk_widget_show(gwVBox);
00190 
00191     // homogenous, spacing
00192     gwHBox = gtk_hbox_new(TRUE, SUI_PADDING);
00193     // expand, fill, padding
00194     gtk_box_pack_start(GTK_BOX(gwVBox), gwHBox, TRUE, TRUE, 0);
00195     gtk_widget_show(gwHBox);
00196 
00197     gwStatusbar = gtk_statusbar_new();
00198     gtk_box_pack_start(GTK_BOX(gwVBox), gwStatusbar, FALSE, FALSE, 0);
00199     guiStatusbarCtxt = gtk_statusbar_get_context_id(
00200         GTK_STATUSBAR(gwStatusbar), "status");
00201     gtk_statusbar_push(GTK_STATUSBAR(gwStatusbar), guiStatusbarCtxt, "");
00202     gtk_widget_show(gwStatusbar);
00203 
00204     MutexData.Wait();
00205     iWidgetCount = iChCount;
00206     iLocalOctaves = iOctaveCount;
00207     lSpectSize = lSampleCount + 1L;
00208     MutexData.Release();
00209     for (iWidgetCntr = 0; iWidgetCntr < iWidgetCount; iWidgetCntr++)
00210     {
00211         SoundChGUI[iWidgetCntr] = new clSoundChGUI(gwHBox, iWidgetCntr + 1,
00212             iLocalOctaves, lSpectSize);
00213     }
00214 
00215     ConnectSignals();
00216 
00217     // Delayed realization of main window
00218     gtk_widget_show(gwWindow);
00219 }
00220 
00221 
00222 void clSoundUI::ConnectSignals ()
00223 {
00224     int iWidgetCntr;
00225     int iWidgetCount;
00226     int iObjectCntr;
00227     int iObjectCount;
00228     int iObjectMask;
00229 
00230     gtk_signal_connect(GTK_OBJECT(gwWindow), "delete-event", 
00231         GTK_SIGNAL_FUNC(WrapOnDeleteEvent), NULL);
00232     MutexData.Wait();
00233     iWidgetCount = iChCount;
00234     iObjectCount = iOctaveCount;
00235     MutexData.Release();
00236     for (iWidgetCntr = 0; iWidgetCntr < iWidgetCount; iWidgetCntr++)
00237     {
00238         gtk_signal_connect(GTK_OBJECT(SoundChGUI[iWidgetCntr]->gwBConnect),
00239             "clicked", GTK_SIGNAL_FUNC(WrapOnClickedEvent), 
00240             GINT_TO_POINTER(iWidgetCntr));
00241         gtk_signal_connect(GTK_OBJECT(SoundChGUI[iWidgetCntr]->gwCBEq),
00242             "toggled", GTK_SIGNAL_FUNC(WrapOnToggledEvent),
00243             GINT_TO_POINTER(iWidgetCntr));
00244         gtk_signal_connect(GTK_OBJECT(SoundChGUI[iWidgetCntr]->goAOutputLevel),
00245             "value-changed", GTK_SIGNAL_FUNC(WrapOnValueChangedEvent),
00246             GINT_TO_POINTER(iWidgetCntr << 16));
00247         for (iObjectCntr = 0; iObjectCntr < iObjectCount; iObjectCntr++)
00248         {
00249             iObjectMask = (iWidgetCntr << 16);
00250             iObjectMask |= ((iObjectCntr + 1) & 0xffff);
00251             gtk_signal_connect(
00252                 GTK_OBJECT(SoundChGUI[iWidgetCntr]->goaAEqLevel[iObjectCntr]),
00253                 "value-changed", GTK_SIGNAL_FUNC(WrapOnValueChangedEvent),
00254                 GINT_TO_POINTER(iObjectMask));
00255         }
00256         gtk_signal_connect(GTK_OBJECT(SoundChGUI[iWidgetCntr]->gwBApplyCurve),
00257             "clicked", GTK_SIGNAL_FUNC(WrapOnApplyCurveClicked),
00258             GINT_TO_POINTER(iWidgetCntr));
00259         gtk_signal_connect(GTK_OBJECT(SoundChGUI[iWidgetCntr]->gwCurveEq),
00260             "motion_notify_event", GTK_SIGNAL_FUNC(WrapOnMotionCurve), 
00261             GINT_TO_POINTER(iWidgetCntr));
00262     }
00263 }
00264 
00265 
00266 bool clSoundUI::ParseServerStr (char *cpHostRes, int *ipPortRes,
00267     const char *cpSourceStr)
00268 {
00269     char cpTempStr[SUI_SERV_MAXLEN + 1];
00270     char *cpTempHost;
00271     char *cpTempPort;
00272 
00273     strncpy(cpTempStr, cpSourceStr, SUI_SERV_MAXLEN);
00274     cpTempHost = strtok(cpTempStr, ": \t\n");
00275     if (cpTempHost != NULL)
00276     {
00277         strcpy(cpHostRes, cpTempHost);
00278         cpTempPort = strtok(NULL, " \t\n");
00279         if (cpTempPort != NULL)
00280         {
00281             *ipPortRes = atoi(cpTempPort);
00282             if (*ipPortRes > 0) return true;
00283         }
00284     }
00285     return false;
00286 }
00287 
00288 
00289 clSoundUI::clSoundUI (int *ArgC, char ***ArgV)
00290 {
00291     int iInitCntr;
00292     
00293     bRun = true;
00294     bFirstTimeout = true;
00295     lDataRefCount = 0L;
00296     for (iInitCntr = 0; iInitCntr < SUI_MAX_CHANNELS; iInitCntr++)
00297     {
00298         bpConnected[iInitCntr] = false;
00299     }
00300 
00301     g_print("%s v%i.%i.%i\n", cpWindowTxt,
00302         SUI_VER_MAJ, SUI_VER_MIN, SUI_VER_PL);
00303     g_print("Copyright (C) 2000-2001 Jussi Laako\n\n");
00304     g_print("Gtk+ version %i.%i.%i\n", gtk_major_version, gtk_minor_version,
00305         gtk_micro_version);
00306     g_print("Locale set to %s\n", gtk_set_locale());
00307     gtk_init(ArgC, ArgV);
00308 }
00309 
00310 
00311 clSoundUI::~clSoundUI ()
00312 {
00313 }
00314 
00315 
00316 int clSoundUI::Exec ()
00317 {
00318     int iChBufSize;
00319     int iAllocCntr;
00320     double dNyquist;
00321     clDSPOp DSP;
00322 
00323     GetCfg();
00324     if (iDeviceBase < 0)
00325     {
00326         pthread_create(&ptidSoundOut, NULL, WrapSoundOutThread, NULL);
00327         SemStart1.Wait();
00328     }
00329     iChBufSize = lSampleCount * sizeof(GDT);
00330     for (iAllocCntr = 0; iAllocCntr < iChCount; iAllocCntr++)
00331     {
00332         ChData[iAllocCntr].Size(iChBufSize);
00333         EqCoeffs[iAllocCntr].Size((lSampleCount + 1L) * sizeof(GDT));
00334         ChData[iAllocCntr].Lock();
00335         EqCoeffs[iAllocCntr].Lock();
00336         DSP.Zero((GDT *) ChData[iAllocCntr], lSampleCount);
00337         DSP.Set((GDT *) EqCoeffs[iAllocCntr], (GDT) 1.0, lSampleCount + 1L);
00338         fpLevelCoeff[iAllocCntr] = (GDT) 1.0;
00339         GDT *fpNullPtr = NULL;
00340         bpEqEnabled[iAllocCntr] = false;
00341         Filters[iAllocCntr].Initialize((long) lSampleCount, fpNullPtr,
00342             SUI_FILTER_WINDOW);
00343     }
00344     MutexData.Wait();
00345     dNyquist = iSampleRate / 2.0;
00346     iOctaveCount = (int) (log(dNyquist) / log(2.0) + 0.5);
00347     if (iOctaveCount > SUI_EQ_MAXOCTS) iOctaveCount = SUI_EQ_MAXOCTS;
00348     MutexData.Release();
00349     if (iDeviceBase < 0) SemStart2.Post();
00350     BuildGUI();
00351     gtk_timeout_add(iVuTimeout, WrapOnTimeoutEvent, NULL);
00352     gtk_main();
00353     if (iDeviceBase < 0) pthread_join(ptidSoundOut, NULL);
00354     for (iAllocCntr = 0; iAllocCntr < iChCount; iAllocCntr++)
00355     {
00356         MutexData.Wait();
00357         if (bpConnected[iAllocCntr]) 
00358         {
00359             bpConnected[iAllocCntr] = false;
00360             CondData[iAllocCntr].Notify();
00361             MutexData.Release();
00362             pthread_join(ptidSoundIn[iAllocCntr], NULL);
00363         }
00364         else MutexData.Release();
00365     }
00366     return 0;
00367 }
00368 
00369 
00370 gboolean clSoundUI::OnDeleteEvent (GtkWidget *gwSender, GdkEvent *geEvent,
00371     gpointer gpData)
00372 {
00373     MutexData.Wait();
00374     bRun = false;
00375     MutexData.Release();
00376     gtk_main_quit();
00377     return TRUE;
00378 }
00379 
00380 
00381 void clSoundUI::OnClickedEvent (GtkButton *gbButton, gpointer gpData)
00382 {
00383     int iChannel = GPOINTER_TO_INT(gpData);
00384     int iPort;
00385     int iSockHandle;
00386     int iSourceChannel;
00387     int iThreadMask;
00388     char cpServer[SUI_SERV_MAXLEN];
00389     GtkWidget *gwServerEntry;
00390 
00391     // Stop running input thread
00392     MutexData.Wait();
00393     if (bpConnected[iChannel])
00394     {
00395         bpConnected[iChannel] = false;
00396         MutexData.Release();
00397         pthread_join(ptidSoundIn[iChannel], NULL);
00398     }
00399     else MutexData.Release();
00400     // Get server entry, source channel number and generated thread mask
00401     gwServerEntry = GTK_COMBO(SoundChGUI[iChannel]->gwCServer)->entry;
00402     iSourceChannel = gtk_spin_button_get_value_as_int(
00403         GTK_SPIN_BUTTON(SoundChGUI[iChannel]->gwSBChannel)) - 1;
00404     iThreadMask = ((iSourceChannel << 16) | iChannel);
00405     // Parse server string and try to connect specified sound server
00406     if (ParseServerStr(cpServer, &iPort, 
00407         gtk_entry_get_text(GTK_ENTRY(gwServerEntry))))
00408     {
00409         iSockHandle = SClient.Connect(cpServer, NULL, iPort);
00410         if (iSockHandle >= 0)
00411         {
00412             MutexData.Wait();
00413             bpConnected[iChannel] = true;
00414             ipSockH[iChannel] = iSockHandle;
00415             MutexData.Release();
00416             pthread_create(&ptidSoundIn[iChannel], NULL, WrapSoundInThread,
00417                 GINT_TO_POINTER(iThreadMask));
00418         }
00419         else
00420         {
00421             g_print("Connect failed!\n");
00422         }
00423     }
00424     else
00425     {
00426         g_print("Invalid entry, format is <server>:<port>\n");
00427     }
00428 }
00429 
00430 
00431 gint clSoundUI::OnTimeoutEvent (gpointer gpData)
00432 {
00433     bool bTypeSet = false;
00434     int iLocalChCount;
00435     int iChCntr;
00436     gfloat fThisInLevel;
00437     gfloat fThisOutLevel;
00438 
00439     MutexData.Wait();
00440     iLocalChCount = iChCount;
00441     MutexData.Release();
00442     for (iChCntr = 0; iChCntr < iLocalChCount; iChCntr++)
00443     {
00444         MutexLevel.Wait();
00445         fThisInLevel = fpInputLevel[iChCntr];
00446         fThisOutLevel = fpOutputLevel[iChCntr];
00447         MutexLevel.Release();
00448         gtk_progress_set_value(
00449             GTK_PROGRESS(SoundChGUI[iChCntr]->gwPBInputLevel), fThisInLevel);
00450         gtk_progress_set_value(
00451             GTK_PROGRESS(SoundChGUI[iChCntr]->gwPBOutputLevel), fThisOutLevel);
00452         if (bFirstTimeout && 
00453             GTK_WIDGET_REALIZED(SoundChGUI[iChCntr]->gwCurveEq))
00454         {
00455             gtk_curve_set_curve_type(GTK_CURVE(SoundChGUI[iChCntr]->gwCurveEq),
00456                 GTK_CURVE_TYPE_LINEAR);
00457             bTypeSet = true;
00458         }
00459     }
00460     if (bTypeSet) bFirstTimeout = false;
00461     return TRUE;
00462 }
00463 
00464 
00465 void clSoundUI::OnToggledEvent (GtkToggleButton *gtbToggleButton, 
00466     gpointer gpData)
00467 {
00468     bool bToggled;
00469     int iThisCh = GPOINTER_TO_INT(gpData);
00470 
00471     bToggled = 
00472         (gtk_toggle_button_get_active(gtbToggleButton)) ? true : false;
00473     MutexFilter[iThisCh].Wait();
00474     bpEqEnabled[iThisCh] = bToggled;
00475     MutexFilter[iThisCh].Release();
00476 }
00477 
00478 
00479 void clSoundUI::OnValueChangedEvent (GtkAdjustment *gaAdjustment, 
00480     gpointer gpData)
00481 {
00482     int iThisCh;
00483     int iThisObj;
00484     long lCoeffCntr;
00485     long lCoeffCount;
00486     long lStartIdx;
00487     long lCenterIdx;
00488     long lEndIdx;
00489     long lDist;
00490     double dNyquist;
00491     double dResolution;
00492     GDT fValue;
00493     GDT fCoeff;
00494     GDT fPrevCoeff;
00495     GDT fNextCoeff;
00496     GDT fDiff;
00497     GDT *fpCoeffPtr;
00498 
00499     iThisCh = (GPOINTER_TO_INT(gpData) >> 16);
00500     iThisObj = (GPOINTER_TO_INT(gpData) & 0xffff);
00501     fValue = -(gaAdjustment->value);
00502     fpCoeffPtr = EqCoeffs[iThisCh];
00503 
00504     if (iThisObj == 0)
00505     {
00506         MutexFilter[iThisCh].Wait();
00507         fpLevelCoeff[iThisCh] = (GDT) pow(10.0, fValue / 20.0);
00508         MutexFilter[iThisCh].Release();
00509         return;
00510     }
00511     
00512     MutexData.Wait();
00513     lCoeffCount = lSampleCount + 1L;
00514     dNyquist = iSampleRate / 2.0;
00515     MutexData.Release();
00516     dResolution = dNyquist / lCoeffCount;
00517     lStartIdx = (long) (pow(2.0, iThisObj - 1) / dResolution + 0.5);
00518     lCenterIdx = (long) (pow(2.0, iThisObj) / dResolution + 0.5);
00519     lEndIdx = (long) (pow(2.0, iThisObj + 1) / dResolution + 0.5);
00520     if (lStartIdx < 0) lStartIdx = 1L;
00521     if (lCenterIdx < 0) lCenterIdx = 1L;
00522     else if (lCenterIdx > lCoeffCount) lCenterIdx = lCoeffCount - 1L;
00523     if (lEndIdx > lCoeffCount) lEndIdx = lCoeffCount - 1L;
00524     fPrevCoeff = fpCoeffPtr[lStartIdx - 1L];
00525     fNextCoeff = fpCoeffPtr[lEndIdx];
00526     fCoeff = pow(10.0, fValue / 20.0);
00527     for (lCoeffCntr = lStartIdx; lCoeffCntr < lEndIdx; lCoeffCntr++)
00528     {
00529         if (lCoeffCntr < lCenterIdx)
00530         {
00531             fDiff = fCoeff - fPrevCoeff;
00532             lDist = lCenterIdx - lStartIdx;
00533             fpCoeffPtr[lCoeffCntr] = 
00534                 fPrevCoeff + fDiff / lDist * (lCoeffCntr - lStartIdx + 1);
00535         }
00536         else
00537         {
00538             fDiff = fCoeff - fNextCoeff;
00539             lDist = lEndIdx - lCenterIdx;
00540             fpCoeffPtr[lCoeffCntr] =
00541                 fNextCoeff + fDiff / lDist * (lEndIdx - lCoeffCntr);
00542         }
00543     }
00544     if (iDCBlock > 0) fpCoeffPtr[0] = (GDT) 0.0;
00545     MutexFilter[iThisCh].Wait();
00546     Filters[iThisCh].SetCoeffs(fpCoeffPtr);
00547     MutexFilter[iThisCh].Release();
00548 
00549     #ifdef __GNUG__
00550     gfloat fpCurveValues[lCoeffCount];
00551     #else
00552     gfloat *fpCurveValues;
00553     clDSPAlloc CurveValues;
00554     fpCurveValues = (gfloat *) CurveValues.Size(lCoeffCount * sizeof(gfloat));
00555     #endif
00556     
00557     for (lCoeffCntr = 0L; lCoeffCntr < lCoeffCount; lCoeffCntr++)
00558     {
00559         fpCurveValues[lCoeffCntr] = 20.0 * log10(fpCoeffPtr[lCoeffCntr]);
00560     }
00561     gtk_curve_set_vector(GTK_CURVE(SoundChGUI[iThisCh]->gwCurveEq),
00562         lCoeffCount, fpCurveValues);
00563     gtk_curve_set_curve_type(GTK_CURVE(SoundChGUI[iThisCh]->gwCurveEq),
00564         GTK_CURVE_TYPE_LINEAR);
00565 }
00566 
00567 
00568 void clSoundUI::OnApplyCurveClicked (GtkButton *gbButton, gpointer gpData)
00569 {
00570     int iThisCh = GPOINTER_TO_INT(gpData);
00571     long lCoeffCntr;
00572     MutexData.Wait();
00573     long lCoeffCount = lSampleCount + 1L;
00574     MutexData.Release();
00575     #ifdef __GNUG__
00576     gfloat fpCurveValues[lCoeffCount];
00577     #else
00578     clDSPAlloc CurveValues;
00579     gfloat *fpCurveValues = (gfloat *) 
00580         CurveValues.Size(lCoeffCount * sizeof(gfloat));
00581     #endif
00582     GDT *fpCoeffPtr = EqCoeffs[iThisCh];
00583 
00584     gtk_curve_get_vector(GTK_CURVE(SoundChGUI[iThisCh]->gwCurveEq),
00585         lCoeffCount, fpCurveValues);
00586     for (lCoeffCntr = 0L; lCoeffCntr < lCoeffCount; lCoeffCntr++)
00587     {
00588         fpCoeffPtr[lCoeffCntr] = 
00589             (GDT) pow(10.0, fpCurveValues[lCoeffCntr] / 20.0);
00590     }
00591     if (iDCBlock > 0) fpCoeffPtr[0] = (GDT) 0.0;
00592     MutexFilter[iThisCh].Wait();
00593     Filters[iThisCh].SetCoeffs(fpCoeffPtr);
00594     MutexFilter[iThisCh].Release();
00595 }
00596 
00597 
00598 void clSoundUI::OnMotionCurve (GtkWidget *gwSender, GdkEventMotion *gemEvent,
00599     gpointer gpData)
00600 {
00601     int iThisCh = GPOINTER_TO_INT(gpData);
00602     char cpStatusTxt[SUI_CONV_LEN];
00603     int iWidth;
00604     int iHeight;
00605     gfloat fResolution;
00606     gfloat fFreqScale;
00607     gfloat fHzValue;
00608     gfloat fdBValue;
00609 
00610     iWidth = SoundChGUI[iThisCh]->gwCurveEq->allocation.width;
00611     iHeight = SoundChGUI[iThisCh]->gwCurveEq->allocation.height;
00612     MutexData.Wait();
00613     fResolution = iSampleRate / 2.0 / (lSampleCount + 1L);
00614     fFreqScale = (gfloat) (lSampleCount + 1L) / (gfloat) iWidth;
00615     MutexData.Release();
00616     fHzValue = gemEvent->x * fFreqScale * fResolution;
00617     fdBValue = (iHeight - gemEvent->y) * (SUI_EQ_RANGE * 2.0 / iHeight) -
00618         SUI_EQ_RANGE;
00619     g_snprintf(cpStatusTxt, SUI_CONV_LEN, "%.1f Hz  %.2f dB", 
00620         fHzValue, fdBValue);
00621     gtk_statusbar_pop(GTK_STATUSBAR(gwStatusbar), guiStatusbarCtxt);
00622     gtk_statusbar_push(GTK_STATUSBAR(gwStatusbar), guiStatusbarCtxt,
00623         cpStatusTxt);
00624 }
00625 
00626 
00627 void *clSoundUI::SoundOutThread (void *vpData)
00628 {
00629     bool bLocalRun = true;
00630     #ifndef __QNX__
00631     int iFormat = SUI_SND_FORMAT;
00632     #endif
00633     int iLocalCh;
00634     int iLocalSR;
00635 
00636     MutexData.Wait();
00637     iLocalCh = iChCount;
00638     iLocalSR = iSampleRate;
00639     MutexData.Release();
00640     if (!bALSA)
00641     {
00642         #ifndef __QNX__
00643         if (Audio.Open(cpDevice, &iFormat, &iLocalSR, &iLocalCh, AUDIO_WRITE))
00644         {
00645             g_print("Audio device open; fs %i ch %i fmt %xh\n", iLocalSR,
00646                 iLocalCh, iFormat);
00647             MutexData.Wait();
00648             iChCount = iLocalCh;
00649             iSampleRate = iLocalSR;
00650             MutexData.Release();
00651         }
00652         else
00653         {
00654             g_print("Unable to open audio device, reason: %s\n",
00655                 strerror(Audio.GetError()));
00656             bLocalRun = false;
00657         }
00658         #else
00659         g_warning("OSS is not supported under QNX");
00660         #endif
00661     }
00662     else
00663     {
00664         #ifndef BSDSYS
00665         if (AudioA.CardOpen(iALSACard))
00666         {
00667             #ifdef USE_ALSA05
00668             if (AudioA.PcmOpen(iALSADevice, iALSASubDevice, AA_MODE_PLAY))
00669             #else
00670             sprintf(cpDevice, "plughw:%i,%i", iALSACard, iALSADevice);
00671             if (AudioA.PcmOpen(cpDevice, AA_MODE_PLAY))
00672             #endif
00673             {
00674                 #ifdef USE_ALSA05
00675                 if (AudioA.PcmSetSetup(iLocalCh, iLocalSR, SUI_SND_BITS,
00676                     SUI_SND_QUEUESIZE, false))
00677                 #else
00678                 if (AudioA.PcmSetSetup(iLocalCh, iLocalSR, SUI_SND_BITS,
00679                     SUI_SND_QUEUESIZE, 2))
00680                 #endif
00681                 {
00682                     if (AudioA.PcmPrepare())
00683                     {
00684                         iLocalCh = AudioA.PcmGetChannels();
00685                         iLocalSR = AudioA.PcmGetSampleRate();
00686                         g_print("Audio device open; fs %i ch %i wl %i\n", 
00687                             iLocalSR, iLocalCh, 
00688                             AudioA.PcmGetBits());
00689                         MutexData.Wait();
00690                         iChCount = iLocalCh;
00691                         iSampleRate = iLocalSR;
00692                         MutexData.Release();
00693                     }
00694                     else
00695                     {
00696                         g_print("ALSA PCM prepare failed\n");
00697                         bLocalRun = false;
00698                     }
00699                 }
00700                 else
00701                 {
00702                     g_print("ALSA PCM setup failed\n");
00703                     g_print("%s\n", AudioA.PcmGetStatusStr(AudioA.PcmGetStatus()));
00704                     bLocalRun = false;
00705                 }
00706             }
00707             else
00708             {
00709                 g_print("ALSA PCM open failed\n");
00710                 bLocalRun = false;
00711             }
00712         }
00713         else
00714         {
00715             g_print("ALSA card open failed\n");
00716             bLocalRun = false;
00717         }
00718         #else
00719         g_warning("ALSA not supported under BSD systems");
00720         #endif        
00721     }
00722     SemStart1.Post();
00723     SemStart2.Wait();
00724 
00725     long lChMask;
00726     long lChCntr;
00727     long lSampleCntr;
00728     long lLocalSC;
00729     volatile long lLocalRefCount;
00730     long lOutDataCount;
00731     long lOutBufSize;
00732     GDT *fpChBuf;
00733     GDT *fpOutBuf;
00734     SUI_SND_DATATYPE *ipOutBuf;
00735     // Priority stuff
00736     #ifndef BSDSYS
00737     int iSchedPolicy;
00738     uid_t uidCurrent;
00739     struct sched_param sSchedParam;
00740     #endif
00741     // -
00742     clDSPAlloc OutBuf1;
00743     clDSPAlloc OutBuf2;
00744     clDSPOp DSP;
00745 
00746     MutexData.Wait();
00747     lLocalSC = lSampleCount;
00748     MutexData.Release();
00749     lOutDataCount = lLocalSC * iLocalCh;
00750     fpOutBuf = (GDT *) OutBuf1.Size(lOutDataCount * sizeof(GDT));
00751     lOutBufSize = lLocalSC * iLocalCh * sizeof(SUI_SND_DATATYPE);
00752     ipOutBuf = (SUI_SND_DATATYPE *) OutBuf2.Size(lOutBufSize);
00753     OutBuf1.Lock();
00754     OutBuf2.Lock();
00755     #ifndef BSDSYS
00756     uidCurrent = getuid();
00757     setuid(0);
00758     pthread_getschedparam(ptidSoundOut, &iSchedPolicy, &sSchedParam);
00759     sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) + 2;
00760     if (pthread_setschedparam(ptidSoundOut, SCHED_FIFO, &sSchedParam) != 0)
00761     {
00762         g_print("SoundOut unable to set scheduling policy\n");
00763     }
00764     setuid(uidCurrent);
00765     /*sSchedParam.sched_priority = 2;
00766     pthread_setschedparam(ptidSoundOut, SCHED_OTHER, &sSchedParam);*/
00767     #endif
00768     g_print("SoundOut thread running\n");
00769     DSP.Zero(fpOutBuf, lOutDataCount);
00770     #ifndef BSDSYS
00771     #ifdef USE_ALSA05
00772     if (bALSA) AudioA.PcmGo();
00773     #else
00774     if (bALSA) AudioA.PcmStart();
00775     #endif
00776     #endif
00777     while (bLocalRun)
00778     {
00779         for (lChCntr = 0; lChCntr < iLocalCh; lChCntr++)
00780         {
00781             lChMask = (1L << lChCntr);
00782             MutexData.Wait();
00783             lLocalRefCount = lDataRefCount;
00784             MutexData.Release();
00785             // --- This one is nasty piece of code, we shouldn't need this
00786             //     but Linux is far from realtime OS, so we can try to
00787             //     give it some extra time to meet the deadline...
00788             if (!(lLocalRefCount & lChMask))
00789             {
00790                 usleep((unsigned long) (lLocalSC / 2 / iLocalSR * 1000000));
00791                 MutexData.Wait();
00792                 lLocalRefCount = lDataRefCount;
00793                 MutexData.Release();
00794             }
00795             // ---
00796             if ((lLocalRefCount & lChMask) == lChMask)
00797             {
00798                 MutexChData[lChCntr].Wait();
00799                 fpChBuf = ChData[lChCntr];
00800                 for (lSampleCntr = 0; lSampleCntr < lLocalSC; lSampleCntr++)
00801                 {
00802                     fpOutBuf[lSampleCntr * iLocalCh + lChCntr] = 
00803                         fpChBuf[lSampleCntr];
00804                 }
00805                 MutexData.Wait();
00806                 lDataRefCount &= ~(lChMask);
00807                 MutexData.Release();
00808                 CondData[lChCntr].Notify();
00809                 MutexChData[lChCntr].Release();
00810             }
00811             else
00812             {
00813                 for (lSampleCntr = 0; lSampleCntr < lLocalSC; lSampleCntr++)
00814                 {
00815                     fpOutBuf[lSampleCntr * iLocalCh + lChCntr] = (GDT) 0.0;
00816                 }
00817                 MutexChData[lChCntr].Wait();
00818                 CondData[lChCntr].Notify();
00819                 MutexChData[lChCntr].Release();
00820             }
00821         }
00822         DSP.Convert(ipOutBuf, fpOutBuf, lOutDataCount, false);
00823         if (!bALSA)
00824         {
00825             #ifndef __QNX__
00826             if (Audio.Write(ipOutBuf, lOutBufSize) < lOutBufSize)
00827                 g_warning("Write to PCM device failed!");
00828             #endif
00829         }
00830         else
00831         {
00832             #ifndef BSDSYS
00833             /*if (AudioA.PcmWrite(ipOutBuf, lOutBufSize) < lOutBufSize)
00834                 g_warning("Write to PCM device failed!");*/
00835             AudioA.PcmWrite(ipOutBuf, lOutBufSize);
00836             #endif
00837         }
00838         MutexData.Wait();
00839         bLocalRun = bRun;
00840         MutexData.Release();
00841     }
00842     if (!bALSA)
00843     {
00844         #ifndef __QNX__
00845         Audio.Reset();
00846         Audio.Close();
00847         #endif
00848     }
00849     else
00850     {
00851         #ifndef BSDSYS
00852         AudioA.PcmClose();
00853         AudioA.CardClose();
00854         #endif
00855     }
00856     g_print("SoundOut thread ending\n");
00857     return NULL;
00858 }
00859 
00860 
00861 void *clSoundUI::SoundInThread (void *vpData)
00862 {
00863     bool bLocalRun = true;
00864     int iSrcCh = (GPOINTER_TO_INT(vpData) >> 16);
00865     int iDestCh = (GPOINTER_TO_INT(vpData) & 0xffff);
00866     int iThisIdx = iDestCh;
00867     int iLocalChCount;
00868     long lLocalSC;
00869     int iMsgSize;
00870     char *cpMsgBuf;
00871     char cpHdrBuf[GLOBAL_HEADER_LEN];
00872     stSoundStart sSoundHdr;
00873     clAlloc MsgBuf;
00874     clSoundMsg SoundMsg;
00875     clSockOp SOp;
00876 
00877     MutexData.Wait();
00878     iLocalChCount = iChCount;
00879     lLocalSC = lSampleCount;
00880     SOp.SetHandle(ipSockH[iThisIdx]);
00881     MutexData.Release();
00882     g_print("SoundIn[%i] thread receiving first message...\n", iThisIdx);
00883     if (SOp.ReadSelect(SUI_FIRST_TIMEOUT))
00884     {
00885         if (SOp.ReadN(cpHdrBuf, GLOBAL_HEADER_LEN) == GLOBAL_HEADER_LEN)
00886         {
00887             SoundMsg.GetStart(cpHdrBuf, &sSoundHdr);
00888         }
00889         else bLocalRun = false;
00890     }
00891     iMsgSize = lLocalSC * sSoundHdr.iChannels * sizeof(GDT);
00892     cpMsgBuf = (char *) MsgBuf.Size(iMsgSize);
00893     MsgBuf.Lock();
00894 
00895     bool bWait;
00896     #ifndef __QNX__
00897     int iLocalFmt = SUI_SND_FORMAT;
00898     #endif
00899     int iLocalSR = (int) (sSoundHdr.dSampleRate + 0.5);
00900     int iLocalCh = iChCount;
00901     long lExtCount = lLocalSC * sSoundHdr.iChannels;
00902     long lOutCount = lLocalSC;
00903     long lChMask = (1L << iThisIdx);
00904     #ifndef __QNX__
00905     long lOutBufSize = 0L;
00906     long lSampleCntr;
00907     char cpDeviceName[_POSIX_PATH_MAX];
00908     #endif
00909     gfloat fInLevel;
00910     gfloat fOutLevel;
00911     GDT *fpInBuf;
00912     GDT *fpOutData;
00913     #ifndef __QNX__
00914     SUI_SND_DATATYPE *ipOutData = NULL;
00915     SUI_SND_DATATYPE *ipOutBuf = NULL;
00916     audio_buf_info sAudioBufInfo;
00917     #endif
00918     // Priority stuff
00919     #ifndef BSDSYS
00920     int iSchedPolicy;
00921     uid_t uidCurrent;
00922     struct sched_param sSchedParam;
00923     #endif
00924     // -
00925     clDSPAlloc InBuf;
00926     clDSPAlloc OutData1;
00927     clDSPAlloc OutData2;
00928     clDSPAlloc OutBuf;
00929     #ifndef __QNX__
00930     clAudio Audio;
00931     #endif
00932     clDSPOp DSP;
00933     
00934     if (iDeviceBase >= 0)
00935     {
00936         #ifndef __QNX__
00937         g_snprintf(cpDeviceName, _POSIX_PATH_MAX, "%s%i",
00938             cpDevice, iDeviceBase + iDestCh);
00939         g_print("SoundIn[%i] open device %s : %i fs\n",
00940             iThisIdx, cpDeviceName, iLocalSR);
00941         if (!Audio.Open(cpDeviceName, &iLocalFmt, &iLocalSR, &iLocalCh, 
00942             AUDIO_WRITE))
00943         {
00944             g_print("Fatal: failed to open device %s in SoundIn[%i]\n",
00945                 cpDeviceName, iThisIdx);
00946             return NULL;
00947         }
00948         g_print("SoundIn[%i] device opened at %i fs\n", iThisIdx, iLocalSR);
00949         lOutBufSize = lOutCount * iLocalCh * sizeof(SUI_SND_DATATYPE);
00950         ipOutData = (SUI_SND_DATATYPE *) OutData2.Size(lOutCount * sizeof(SUI_SND_DATATYPE));
00951         ipOutBuf = (SUI_SND_DATATYPE *) OutBuf.Size(lOutBufSize);
00952         OutData2.Lock();
00953         OutBuf.Lock();
00954         memset(ipOutBuf, 0x00, lOutBufSize);
00955         #else
00956         g_warning("This functionality is not supported under QNX");
00957         #endif
00958     }
00959     SOp.SetRecvBufSize(iMsgSize * 2);
00960     fpInBuf = (GDT *) InBuf.Size(lExtCount * sizeof(GDT));
00961     fpOutData = (GDT *) OutData1.Size(lOutCount * sizeof(GDT));
00962     InBuf.Lock();
00963     OutData1.Lock();
00964     #ifndef BSDSYS
00965     uidCurrent = getuid();
00966     setuid(0);
00967     pthread_getschedparam(ptidSoundOut, &iSchedPolicy, &sSchedParam);
00968     sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
00969     if (pthread_setschedparam(ptidSoundOut, SCHED_FIFO, &sSchedParam) != 0)
00970     {
00971         g_print("SoundIn[%i] unable to set scheduling policy\n", iThisIdx);
00972     }
00973     setuid(uidCurrent);
00974     /*sSchedParam.sched_priority = 1;
00975     pthread_setschedparam(ptidSoundOut, SCHED_OTHER, &sSchedParam);*/
00976     #endif
00977     g_print("SoundIn[%i] thread running\n", iThisIdx);
00978     #ifndef __QNX__
00979     if (iDeviceBase >= 0)
00980     {
00981         g_print("SoundIn[%i] prefilling output buffer...\n", iThisIdx);
00982         do {
00983             Audio.Write(ipOutBuf, lOutBufSize);
00984             Audio.GetOutBufInfo(&sAudioBufInfo);
00985         } while (sAudioBufInfo.bytes >= lOutBufSize);
00986     }
00987     #endif
00988     // Wait for one message size
00989     // This is not very clean, but we shouldn't create multilayer buffering
00990     // for latency's sake!
00991     float fTime = 1.0f / (iLocalSR * iLocalCh);
00992     usleep((unsigned long) (lExtCount * fTime * 1000000.0f + 0.5f));
00993     while (bLocalRun)
00994     {
00995         if (SOp.ReadSelect(SUI_IN_TIMEOUT))
00996         {
00997             if (SOp.ReadN(cpMsgBuf, iMsgSize) == iMsgSize)
00998             {
00999                 SoundMsg.GetData(cpMsgBuf, fpInBuf, lExtCount);
01000                 DSP.Extract(fpOutData, fpInBuf, iSrcCh, sSoundHdr.iChannels,
01001                     lExtCount);
01002                 fInLevel = DSP.PeakLevel(fpOutData, lOutCount);
01003                 MutexLevel.Wait();
01004                 fpInputLevel[iThisIdx] = 
01005                     (fpInputLevel[iThisIdx] + fInLevel) * (gfloat) 0.5;
01006                 MutexLevel.Release();
01007                 MutexFilter[iThisIdx].Wait();
01008                 DSP.Mul(fpOutData, fpLevelCoeff[iThisIdx], lOutCount);
01009                 if (bpEqEnabled[iThisIdx])
01010                 {
01011                     Filters[iThisIdx].Put(fpOutData, lOutCount);
01012                     if (!Filters[iThisIdx].Get(fpOutData, lOutCount))
01013                         DSP.Zero(fpOutData, lOutCount);
01014                 }
01015                 MutexFilter[iThisIdx].Release();
01016                 fOutLevel = DSP.PeakLevel(fpOutData, lOutCount);
01017                 MutexLevel.Wait();
01018                 fpOutputLevel[iThisIdx] =
01019                     (fpOutputLevel[iThisIdx] + fOutLevel) * 
01020                     (gfloat) 0.5;
01021                 MutexLevel.Release();
01022                 if (iDeviceBase < 0)
01023                 {
01024                     MutexData.Wait();
01025                     bWait = ((lDataRefCount & lChMask) == lChMask) ?
01026                         true : false;
01027                     MutexData.Release();
01028                     MutexChData[iThisIdx].Wait();
01029                     if (bWait)
01030                     {
01031                         CondData[iThisIdx].Wait(
01032                             MutexChData[iThisIdx].GetPtr());
01033                     }
01034                     DSP.Copy((GDT *) ChData[iThisIdx], fpOutData, lOutCount);
01035                     MutexData.Wait();
01036                     lDataRefCount |= lChMask;
01037                     bLocalRun = bpConnected[iThisIdx];
01038                     MutexData.Release();
01039                     MutexChData[iThisIdx].Release();
01040                 }
01041                 #ifndef __QNX__
01042                 else
01043                 {
01044                     DSP.Convert(ipOutData, fpOutData, lOutCount, false);
01045                     for (lSampleCntr = 0L; 
01046                         lSampleCntr < lOutCount; 
01047                         lSampleCntr++)
01048                     {
01049                         ipOutBuf[lSampleCntr * iLocalCh + iDestCh] =
01050                             ipOutData[lSampleCntr];
01051                     }
01052                     Audio.Write(ipOutBuf, lOutBufSize);
01053                     MutexData.Wait();
01054                     bLocalRun = bpConnected[iThisIdx];
01055                     MutexData.Release();
01056                 }
01057                 #endif
01058             }
01059             else bLocalRun = false;
01060         }
01061         else
01062         {
01063             if (SOp.GetErrno() != 0) bLocalRun = false;
01064         }
01065         MutexData.Wait();
01066         bLocalRun = bpConnected[iThisIdx];
01067         MutexData.Release();
01068     }
01069     SOp.Close();
01070     MutexData.Wait();
01071     bpConnected[iThisIdx] = false;
01072     MutexData.Release();
01073     #ifndef __QNX__
01074     if (iDeviceBase >= 0)
01075     {
01076         Audio.Reset();
01077         Audio.Close();
01078     }
01079     #endif
01080     g_print("SoundIn[%i] thread ending\n", iThisIdx);
01081     return NULL;
01082 }
01083 
01084 
01085 // clSoundChGUI
01086 
01087 
01088 clSoundChGUI::clSoundChGUI (GtkWidget *gwAttachBox, int iChannelNo, 
01089     int iOctaveCount, long lFilterSize)
01090 {
01091     int iOctaveCntr;
01092     char cpConvBuf[SUI_CONV_LEN];
01093     gfloat fFreq;
01094 
01095     g_snprintf(cpConvBuf, SUI_CONV_LEN, "%s %i", cpChannelPfx, iChannelNo);
01096     gwFrame = gtk_frame_new(cpConvBuf);
01097     // expand, fill, padding
01098     gtk_box_pack_start(GTK_BOX(gwAttachBox), gwFrame, TRUE, TRUE, 0);
01099     gtk_widget_show(gwFrame);
01100     // homogenous, spacing
01101     gwVBox = gtk_vbox_new(FALSE, SUI_PADDING);
01102     gtk_container_add(GTK_CONTAINER(gwFrame), gwVBox);
01103     gtk_widget_show(gwVBox);
01104 
01105     // Table 1
01106     // rows, columns, homogenous
01107     gwTable1 = gtk_table_new(2, 3, FALSE);
01108     gtk_box_pack_start(GTK_BOX(gwVBox), gwTable1, FALSE, FALSE, 0);
01109     gtk_widget_show(gwTable1);
01110 
01111     gwLServer = gtk_label_new(cpLServerTxt);
01112     gtk_label_set_justify(GTK_LABEL(gwLServer), GTK_JUSTIFY_LEFT);
01113     gtk_table_attach(GTK_TABLE(gwTable1), gwLServer,
01114         0, 1, 0, 1,
01115         (GtkAttachOptions) (GTK_FILL|GTK_SHRINK|GTK_EXPAND),
01116         (GtkAttachOptions) 0,
01117         SUI_PADDING / 2, 0);
01118     gtk_widget_show(gwLServer);
01119     gwCServer = gtk_combo_new();
01120     gtk_entry_set_max_length(GTK_ENTRY(GTK_COMBO(gwCServer)->entry), 
01121         SUI_SERV_MAXLEN);
01122     gtk_table_attach(GTK_TABLE(gwTable1), gwCServer,
01123         0, 1, 1, 2,
01124         (GtkAttachOptions) (GTK_FILL|GTK_SHRINK|GTK_EXPAND),
01125         (GtkAttachOptions) 0,
01126         SUI_PADDING / 2, 0);
01127     gtk_widget_show(gwCServer);
01128     glServers = NULL;
01129     GtkUtils.ComboListFromFile(gwCServer, &glServers, SUI_HOSTFILE);
01130 
01131     gwLChannel = gtk_label_new(cpLChannelTxt);
01132     gtk_label_set_justify(GTK_LABEL(gwLChannel), GTK_JUSTIFY_LEFT);
01133     gtk_table_attach(GTK_TABLE(gwTable1), gwLChannel,
01134         1, 2, 0, 1,
01135         (GtkAttachOptions) 0,
01136         (GtkAttachOptions) 0,
01137         SUI_PADDING / 2, 0);
01138     gtk_widget_show(gwLChannel);
01139     // value, lower, higher, step, page, page size
01140     goAChannel = gtk_adjustment_new(SUI_CH_VALUE, SUI_CH_LOWER, SUI_CH_HIGHER,
01141         1.0, 1.0, 1.0);
01142     // climb rate, digits
01143     gwSBChannel = gtk_spin_button_new(GTK_ADJUSTMENT(goAChannel),
01144         1.0, 0);
01145     gtk_table_attach(GTK_TABLE(gwTable1), gwSBChannel,
01146         1, 2, 1, 2,
01147         (GtkAttachOptions) 0,
01148         (GtkAttachOptions) 0,
01149         SUI_PADDING / 2, 0);
01150     gtk_widget_show(gwSBChannel);
01151 
01152     gwBConnect = gtk_button_new_with_label(cpBConnectTxt);
01153     gtk_table_attach(GTK_TABLE(gwTable1), gwBConnect,
01154         2, 3, 1, 2,
01155         (GtkAttachOptions) 0,
01156         (GtkAttachOptions) 0,
01157         SUI_PADDING / 2, 0);
01158     gtk_widget_show(gwBConnect);
01159 
01160     gwLInputLevel = gtk_label_new(cpLInputLevelTxt);
01161     gtk_label_set_justify(GTK_LABEL(gwLInputLevel), GTK_JUSTIFY_LEFT);
01162     gtk_box_pack_start(GTK_BOX(gwVBox), gwLInputLevel, FALSE, FALSE, 0);
01163     gtk_widget_show(gwLInputLevel);
01164     gwPBInputLevel = gtk_progress_bar_new();
01165     gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(gwPBInputLevel),
01166         GTK_PROGRESS_LEFT_TO_RIGHT);
01167     gtk_progress_set_show_text(GTK_PROGRESS(gwPBInputLevel), TRUE);
01168     gtk_progress_set_text_alignment(GTK_PROGRESS(gwPBInputLevel),
01169         0.0, 0.5);
01170     gtk_progress_set_format_string(GTK_PROGRESS(gwPBInputLevel),
01171         "%v dB");
01172     //gtk_progress_set_activity_mode(GTK_PROGRESS(gwPBInputLevel), TRUE);
01173     gtk_progress_configure(GTK_PROGRESS(gwPBInputLevel),
01174         SUI_IN_VALUE, SUI_IN_LOWER, SUI_IN_HIGHER);
01175     gtk_box_pack_start(GTK_BOX(gwVBox), gwPBInputLevel, FALSE, FALSE, 0);
01176     gtk_widget_show(gwPBInputLevel);
01177 
01178     gwCBEq = gtk_check_button_new_with_label(cpLEqTxt);
01179     gtk_box_pack_start(GTK_BOX(gwVBox), gwCBEq, FALSE, FALSE, 0);
01180     gtk_widget_show(gwCBEq);
01181     gwTableEq = gtk_table_new(2, iOctaveCount, FALSE);
01182     gtk_box_pack_start(GTK_BOX(gwVBox), gwTableEq, TRUE, TRUE, 0);
01183     gtk_widget_show(gwTableEq);
01184     gwLOutputLevel = gtk_label_new(cpLOutputLevelTxt);
01185     gtk_table_attach(GTK_TABLE(gwTableEq), gwLOutputLevel,
01186         0, 1, 1, 2,
01187         (GtkAttachOptions) (GTK_SHRINK|GTK_EXPAND),
01188         (GtkAttachOptions) 0,
01189         SUI_PADDING / 2, 0);
01190     gtk_widget_show(gwLOutputLevel);
01191     goAOutputLevel = gtk_adjustment_new(0.0, -(SUI_OUT_RANGE), SUI_OUT_RANGE,
01192         SUI_OUT_STEP, 1.0, 1.0);
01193     gwVSOutputLevel = gtk_vscale_new(GTK_ADJUSTMENT(goAOutputLevel));
01194     gtk_scale_set_draw_value(GTK_SCALE(gwVSOutputLevel), FALSE);
01195     gtk_table_attach(GTK_TABLE(gwTableEq), gwVSOutputLevel,
01196         0, 1, 0, 1,
01197         (GtkAttachOptions) (GTK_SHRINK|GTK_EXPAND),
01198         (GtkAttachOptions) (GTK_FILL|GTK_SHRINK|GTK_EXPAND),
01199         SUI_PADDING / 2, 0);
01200     gtk_widget_show(gwVSOutputLevel);
01201     gwPBOutputLevel = gtk_progress_bar_new();
01202     gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(gwPBOutputLevel),
01203         GTK_PROGRESS_BOTTOM_TO_TOP);
01204     gtk_progress_set_show_text(GTK_PROGRESS(gwPBOutputLevel), TRUE);
01205     gtk_progress_set_text_alignment(GTK_PROGRESS(gwPBOutputLevel),
01206         0.5, 1.0);
01207     gtk_progress_set_format_string(GTK_PROGRESS(gwPBOutputLevel),
01208         "%v dB");
01209     //gtk_progress_set_activity_mode(GTK_PROGRESS(gwPBOutputLevel), TRUE);
01210     gtk_progress_configure(GTK_PROGRESS(gwPBOutputLevel),
01211         SUI_OUT_VALUE, SUI_OUT_LOWER, SUI_OUT_HIGHER);
01212     gtk_table_attach(GTK_TABLE(gwTableEq), gwPBOutputLevel,
01213         1, 2, 0, 2,
01214         (GtkAttachOptions) (GTK_SHRINK|GTK_EXPAND),
01215         (GtkAttachOptions) (GTK_FILL|GTK_SHRINK|GTK_EXPAND),
01216         SUI_PADDING / 2, 0);
01217     gtk_widget_show(gwPBOutputLevel);
01218     for (iOctaveCntr = 0; iOctaveCntr < iOctaveCount; iOctaveCntr++)
01219     {
01220         fFreq = pow(2.0, iOctaveCntr + 1);
01221         if (fFreq < 1000.0)
01222             g_snprintf(cpConvBuf, SUI_CONV_LEN, "%.0f", fFreq);
01223         else
01224             g_snprintf(cpConvBuf, SUI_CONV_LEN, "%.1fk", fFreq / 1000.0);
01225         gwaLEqLevel[iOctaveCntr] = gtk_label_new(cpConvBuf);
01226         gtk_table_attach(GTK_TABLE(gwTableEq), gwaLEqLevel[iOctaveCntr],
01227             2 + iOctaveCntr, 3 + iOctaveCntr, 1, 2,
01228             (GtkAttachOptions) (GTK_SHRINK|GTK_EXPAND),
01229             (GtkAttachOptions) 0,
01230             SUI_PADDING / 2, 0);
01231         gtk_widget_show(gwaLEqLevel[iOctaveCntr]);
01232         goaAEqLevel[iOctaveCntr] = gtk_adjustment_new(
01233             0.0, -(SUI_EQ_RANGE), SUI_EQ_RANGE, SUI_EQ_STEP, 1.0, 1.0);
01234         gwaVSEqLevel[iOctaveCntr] = gtk_vscale_new(
01235             GTK_ADJUSTMENT(goaAEqLevel[iOctaveCntr]));
01236         gtk_scale_set_draw_value(GTK_SCALE(gwaVSEqLevel[iOctaveCntr]), FALSE);
01237         gtk_table_attach(GTK_TABLE(gwTableEq), gwaVSEqLevel[iOctaveCntr],
01238             2 + iOctaveCntr, 3 + iOctaveCntr, 0, 1,
01239             (GtkAttachOptions) (GTK_SHRINK|GTK_EXPAND),
01240             (GtkAttachOptions) (GTK_FILL|GTK_SHRINK|GTK_EXPAND),
01241             SUI_PADDING / 2, 0);
01242         gtk_widget_show(gwaVSEqLevel[iOctaveCntr]);
01243     }
01244 
01245     // Curve: Eq
01246     gwCurveEq = gtk_curve_new();
01247     gtk_box_pack_start(GTK_BOX(gwVBox), gwCurveEq, TRUE, TRUE, 0);
01248     gtk_curve_set_range(GTK_CURVE(gwCurveEq), 
01249         0.0, (gfloat) lFilterSize,
01250         -SUI_EQ_RANGE, SUI_EQ_RANGE);
01251         
01252     #ifdef __GNUG__
01253     GDT fpInitVect[lFilterSize];
01254     #else
01255     clDSPAlloc InitVect;
01256     GDT *fpInitVect = (GDT *) InitVect.Size(lFilterSize * sizeof(GDT));
01257     #endif
01258     clDSPOp DSP;
01259     
01260     DSP.Set(fpInitVect, 0.0, lFilterSize);
01261     gtk_curve_set_vector(GTK_CURVE(gwCurveEq), lFilterSize, fpInitVect);
01262     gtk_widget_set_usize(gwCurveEq, gwCurveEq->requisition.width,
01263         gwCurveEq->requisition.width);
01264     gtk_widget_show(gwCurveEq);
01265 
01266     // Button: Apply curve
01267     gwBApplyCurve = gtk_button_new_with_label(cpBApplyCurveTxt);
01268     gtk_box_pack_start(GTK_BOX(gwVBox), gwBApplyCurve, FALSE, FALSE, 0);
01269     gtk_widget_show(gwBApplyCurve);
01270 }
01271 
01272 
01273 clSoundChGUI::~clSoundChGUI ()
01274 {
01275 }
01276 

Generated on Sun Oct 26 19:11:22 2003 for HASAS by doxygen 1.3.3