/*- * Copyright (c) 1999 Thomas Runge (coto@core.de) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #ifdef __NetBSD__ #include #include #else #if defined(linux) || defined(__FreeBSD__) #include #else #include #endif #endif #include "analyzer.h" #include "radio.h" #include "misc.h" #if (XmVERSION < 2) enum { XmUNSET, XmSET, XmINDETERMINATE }; #endif Widget popupW, drawFormW, drawW; Widget vis_anaW, vis_scopeW, ana_normalW, ana_fireW, ana_vertW; Widget ana_linesW, ana_barsW, scope_dotW, scope_lineW, scope_solidW; Widget refresh_fullW, refresh_halfW, refresh_quarterW, refresh_eightW; enum vismodes {VIS_ANA, VIS_SCOPE, ANA_NORMAL, ANA_FIRE, ANA_VERT, ANA_LINES, ANA_BARS, SCOPE_DOT, SCOPE_LINE, SCOPE_SOLID, REFRESH_FULL, REFRESH_HALF, REFRESH_QUARTER, REFRESH_EIGHT}; static const struct { enum vismodes mode; Widget *w; } modeTable[] = { {VIS_ANA, &vis_anaW}, {VIS_SCOPE, &vis_scopeW}, {ANA_NORMAL, &ana_normalW}, {ANA_FIRE, &ana_fireW}, {ANA_VERT, &ana_vertW}, {ANA_LINES, &ana_linesW}, {ANA_BARS, &ana_barsW}, {SCOPE_DOT, &scope_dotW}, {SCOPE_LINE, &scope_lineW}, {SCOPE_SOLID, &scope_solidW}, {REFRESH_FULL, &refresh_fullW}, {REFRESH_HALF, &refresh_halfW}, {REFRESH_QUARTER, &refresh_quarterW}, {REFRESH_EIGHT, &refresh_eightW} }; static sampleStruct ss; static Dimension width, height; static int is_popped; static Widget anConfW; static int vis_mode = VIS_SCOPE; static int ana_mode1 = ANA_NORMAL; static int ana_mode2 = ANA_LINES; static int scope_mode = SCOPE_LINE; static int refresh_mode = REFRESH_FULL; static char gbuf[BUFSIZ]; static void vis_mode_scope(Window win); static void vis_mode_ana(Window win); static void RefreshToggleButtons(int); static void callback_func() { Window win = XtWindow(drawW); switch(vis_mode) { case VIS_SCOPE: vis_mode_scope(win); break; case VIS_ANA: vis_mode_ana(win); break; default: printf("unknown visualization mode!\n"); vis_mode = VIS_SCOPE; break; } } static void vis_mode_ana(Window win) { printf("analyzer mode not ready, yet.\n"); XtCallCallbacks(vis_scopeW, XmNvalueChangedCallback, (XtPointer)NULL); RefreshToggleButtons(False); } static void vis_mode_scope(Window win) { float f; Dimension lastx, lasty, y, j; signed short min, max, i; min = max = audio_buffer[0]; for(i=1; i max) max = audio_buffer[i]; } min = min < 0 ? -min : min; max = max < 0 ? -max : max; max = max > min ? max : min; if(!max) max = 1; f = (float)ss.bufsize / (float)(width); lastx = 0; lasty = audio_buffer[0] * .8 * height/max + height; lasty >>= 1; XClearWindow(dpy, win); XDrawLine(dpy, win, gc, 0, height/2, width, height/2); for(j=0; jtype == MapNotify) { ss.format = SAMPLEFMT; ss.stereo = SAMPLENUMCH; ss.speed = SAMPLESPEED; ss.func = callback_func; switch(ss.format) { case AFMT_U8: case AFMT_S8: ss.bps = 1; break; case AFMT_S16_LE: case AFMT_S16_BE: case AFMT_U16_LE: case AFMT_U16_BE: ss.bps = 2; break; default: sprintf(gbuf, "unsupported sample format: %d\n(trying to handle it)", ss.format); XtomShowMessage(toplevel, XmDIALOG_ERROR, "sampling", gbuf); ss.bps = 2; } SampleStart(&ss); } if(event->type == UnmapNotify) { SampleEnd(); } return; } static void exposeCB(Widget widget, XtPointer clientData, XtPointer callData) { callback_func(); } static void resizeCB(Widget widget, XtPointer clientData, XtPointer callData) { XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL); } static void closeCB(Widget widget, XtPointer clientData, XtPointer callData) { AnalyzerToggle(); } static void visCB(Widget widget, XtPointer clientData, XtPointer callData) { vis_mode = (int)clientData; RefreshToggleButtons(False); } static void ana1CB(Widget widget, XtPointer clientData, XtPointer callData) { ana_mode1 = (int)clientData; RefreshToggleButtons(False); } static void ana2CB(Widget widget, XtPointer clientData, XtPointer callData) { ana_mode2 = (int)clientData; RefreshToggleButtons(False); } static void scopeCB(Widget widget, XtPointer clientData, XtPointer callData) { scope_mode = (int)clientData; RefreshToggleButtons(False); } static void refreshCB(Widget widget, XtPointer clientData, XtPointer callData) { refresh_mode = (int)clientData; RefreshToggleButtons(False); } static void CreateConfigPopup(Widget parent) { Widget vis_modeW, ana_modeW, scope_modeW, refresh_modeW; Widget vis_menuW, ana_menuW, scope_menuW, refresh_menuW; Widget ana_sep1W; Arg args[10]; int n; n=0; XtSetArg(args[n], XmNmenuPost, ""); n++; anConfW = XmCreatePopupMenu(parent, "an_config_popup", args, n); n = 0; XtSetArg(args[n], XmNradioBehavior, True); n++; vis_menuW = XmCreatePulldownMenu(anConfW, "visualization_menu", args, n); ana_menuW = XmCreatePulldownMenu(anConfW, "analyzer_menu", args, n); scope_menuW = XmCreatePulldownMenu(anConfW, "scope_menu", args, n); refresh_menuW = XmCreatePulldownMenu(anConfW, "refresh_menu", args, n); vis_anaW = XtVaCreateManagedWidget("vis_analyzer", xmToggleButtonWidgetClass, vis_menuW, NULL); XtAddCallback(vis_anaW, XmNvalueChangedCallback, visCB, (XtPointer)VIS_ANA); vis_scopeW = XtVaCreateManagedWidget("vis_scope", xmToggleButtonWidgetClass, vis_menuW, NULL); XtAddCallback(vis_scopeW, XmNvalueChangedCallback, visCB, (XtPointer)VIS_SCOPE); ana_normalW = XtVaCreateManagedWidget("ana_normal", xmToggleButtonWidgetClass, ana_menuW, NULL); XtAddCallback(ana_normalW, XmNvalueChangedCallback, ana1CB, (XtPointer)ANA_NORMAL); ana_fireW = XtVaCreateManagedWidget("ana_fire", xmToggleButtonWidgetClass, ana_menuW, NULL); XtAddCallback(ana_fireW, XmNvalueChangedCallback, ana1CB, (XtPointer)ANA_FIRE); ana_vertW = XtVaCreateManagedWidget("ana_vert", xmToggleButtonWidgetClass, ana_menuW, NULL); XtAddCallback(ana_vertW, XmNvalueChangedCallback, ana1CB, (XtPointer)ANA_VERT); ana_sep1W = XtVaCreateManagedWidget("ana_sep", xmSeparatorWidgetClass, ana_menuW, NULL); ana_linesW = XtVaCreateManagedWidget("ana_lines", xmToggleButtonWidgetClass, ana_menuW, NULL); XtAddCallback(ana_linesW, XmNvalueChangedCallback, ana2CB, (XtPointer)ANA_LINES); ana_barsW = XtVaCreateManagedWidget("ana_bars", xmToggleButtonWidgetClass, ana_menuW, NULL); XtAddCallback(ana_barsW, XmNvalueChangedCallback, ana2CB, (XtPointer)ANA_BARS); scope_dotW = XtVaCreateManagedWidget("scope_dot", xmToggleButtonWidgetClass, scope_menuW, NULL); XtAddCallback(scope_dotW, XmNvalueChangedCallback, scopeCB, (XtPointer)SCOPE_DOT); scope_lineW = XtVaCreateManagedWidget("scope_line", xmToggleButtonWidgetClass, scope_menuW, NULL); XtAddCallback(scope_lineW, XmNvalueChangedCallback, scopeCB, (XtPointer)SCOPE_LINE); scope_solidW = XtVaCreateManagedWidget("scope_solid", xmToggleButtonWidgetClass, scope_menuW, NULL); XtAddCallback(scope_solidW, XmNvalueChangedCallback, scopeCB, (XtPointer)SCOPE_SOLID); refresh_fullW = XtVaCreateManagedWidget("refresh_full", xmToggleButtonWidgetClass, refresh_menuW, NULL); XtAddCallback(refresh_fullW, XmNvalueChangedCallback, refreshCB, (XtPointer)REFRESH_FULL); refresh_halfW = XtVaCreateManagedWidget("refresh_half", xmToggleButtonWidgetClass, refresh_menuW, NULL); XtAddCallback(refresh_halfW, XmNvalueChangedCallback, refreshCB, (XtPointer)REFRESH_HALF); refresh_quarterW = XtVaCreateManagedWidget("refresh_quarter", xmToggleButtonWidgetClass, refresh_menuW, NULL); XtAddCallback(refresh_quarterW, XmNvalueChangedCallback, refreshCB, (XtPointer)REFRESH_QUARTER); refresh_eightW = XtVaCreateManagedWidget("refresh_eight", xmToggleButtonWidgetClass, refresh_menuW, NULL); XtAddCallback(refresh_eightW, XmNvalueChangedCallback, refreshCB, (XtPointer)REFRESH_EIGHT); vis_modeW = XtVaCreateManagedWidget("visualization_mode", xmCascadeButtonWidgetClass, anConfW, XmNsubMenuId, vis_menuW, NULL); ana_modeW = XtVaCreateManagedWidget("analyzer_mode", xmCascadeButtonWidgetClass, anConfW, XmNsubMenuId, ana_menuW, NULL); scope_modeW = XtVaCreateManagedWidget("scope_mode", xmCascadeButtonWidgetClass, anConfW, XmNsubMenuId, scope_menuW, NULL); refresh_modeW = XtVaCreateManagedWidget("refresh_mode", xmCascadeButtonWidgetClass, anConfW, XmNsubMenuId, refresh_menuW, NULL); RefreshToggleButtons(True); } void RefreshToggleButtons(int callcallbacks) { int i, size; size = sizeof(modeTable) / sizeof(modeTable[0]); for(i=0; itype == ButtonPress || event->type == ButtonRelease) { if(event->xbutton.button == Button3) XmMenuPosition(anConfW, &event->xbutton); } else { XQueryPointer(dpy, XtWindow(w), &w1, &w2, &bEvent.x_root, &bEvent.y_root, &i1, &i2, &i3); XmMenuPosition(anConfW, &bEvent); } XtManageChild(anConfW); } static void MakeInterface(Widget topl) { Position x, y; Dimension w, h; extern void _XEditResCheckMessages(Widget, XtPointer, XEvent*, Boolean*); XtVaGetValues(topl, XmNx, &x, XmNy, &y, XmNwidth, &w, XmNheight, &h, NULL); popupW = XtVaCreatePopupShell("analyzer", transientShellWidgetClass, topl, XmNx, x, XmNy, y, XmNwidth, w, XmNheight, h, XmNdeleteResponse, XmDO_NOTHING, XtNiconPixmap, icon_pm, XtNiconMask, icon_pm_mask, NULL); drawFormW = XtVaCreateManagedWidget("analyzerdrawform", xmFormWidgetClass, popupW, NULL); drawW = XtVaCreateManagedWidget("analyzerdraw", xmDrawingAreaWidgetClass, drawFormW, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 2, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 2, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 2, NULL); XtAddCallback(drawW, XmNexposeCallback, exposeCB, (XtPointer)NULL); XtAddCallback(drawW, XmNresizeCallback, resizeCB, (XtPointer)NULL); CreateConfigPopup(popupW); XtAddEventHandler(popupW, (EventMask)0, True, _XEditResCheckMessages, NULL); XtAddEventHandler(popupW, StructureNotifyMask, False, (XtEventHandler) iconifyCB, (XtPointer)NULL); /* not ready, yet. XtAddEventHandler(popupW, ButtonPressMask, False, (XtEventHandler) analyzer_config_popup, (XtPointer)NULL); */ } void AnalyzerQuit() { if(popupW) { if(is_popped) { is_popped = False; XtPopdown(popupW); } } } void AnalyzerToggle() { if(!popupW) { // init Atom wmDeleteAtom; is_popped = False; MakeInterface(toplevel); #ifdef HAS_XPM if(skin) SkinToWidgets(popupW, skin); #endif wmDeleteAtom = XmInternAtom(dpy, "WM_DELETE_WINDOW", False); XmAddWMProtocolCallback(popupW, wmDeleteAtom, closeCB, (XtPointer)NULL); } if(is_popped) { is_popped = False; XtPopdown(popupW); } else { is_popped = True; XtPopup(popupW, XtGrabNone); } }