]> git.alsa-project.org Git - alsa-tools.git/commitdiff
Initial version
authorJaroslav Kysela <perex@perex.cz>
Sun, 29 Oct 2000 21:51:51 +0000 (21:51 +0000)
committerJaroslav Kysela <perex@perex.cz>
Sun, 29 Oct 2000 21:51:51 +0000 (21:51 +0000)
12 files changed:
envy24control/AUTHORS [new file with mode: 0644]
envy24control/COPYING [new file with mode: 0644]
envy24control/Makefile.am [new file with mode: 0644]
envy24control/configure.in [new file with mode: 0644]
envy24control/cvscompile [new file with mode: 0644]
envy24control/driverevents.c [new file with mode: 0644]
envy24control/envy24control.c [new file with mode: 0644]
envy24control/envy24control.h [new file with mode: 0644]
envy24control/hardware.c [new file with mode: 0644]
envy24control/levelmeters.c [new file with mode: 0644]
envy24control/mixer.c [new file with mode: 0644]
envy24control/patchbay.c [new file with mode: 0644]

diff --git a/envy24control/AUTHORS b/envy24control/AUTHORS
new file mode 100644 (file)
index 0000000..8b658f1
--- /dev/null
@@ -0,0 +1 @@
+Jaroslav Kysela <perex@suse.cz>
diff --git a/envy24control/COPYING b/envy24control/COPYING
new file mode 100644 (file)
index 0000000..9392a19
--- /dev/null
@@ -0,0 +1,282 @@
+GNU GENERAL PUBLIC LICENSE
+
+Version 2, June 1991 
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public
+License applies to most of the Free Software Foundation's software and to
+any other program whose authors commit to using it. (Some other
+Free Software Foundation software is covered by the GNU Library General
+Public License instead.) You can apply it to your programs, too. 
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this service
+if you wish), that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free programs;
+and that you know you can do these things. 
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it. 
+
+For example, if you distribute copies of such a program, whether gratis or
+for a fee, you must give the recipients all the rights that you have. You
+must make sure that they, too, receive or can get the source code. And you
+must show them these terms so they know their rights. 
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy,
+distribute and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software.
+If the software is modified by someone else and passed on, we want its
+recipients to know that what they have is not the original, so that any
+problems introduced by others will not reflect on the original authors'
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent must be
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under
+the terms of this General Public License. The "Program", below, refers to
+any such program or work, and a "work based on the Program" means
+either the Program or any derivative work under copyright law: that is to
+say, a work containing the Program or a portion of it, either verbatim
+or with modifications and/or translated into another language. (Hereinafter,
+translation is included without limitation in the term
+"modification".) Each licensee is addressed as "you". 
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the
+Program is not restricted, and the output from the Program is covered only
+if its contents constitute a work based on the Program (independent
+of having been made by running the Program). Whether that is true depends on
+what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code
+as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+License and to the absence of any warranty; and give any other recipients of
+the Program a copy of this License along with the Program. 
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided that
+you also meet all of these conditions: 
+
+    a) You must cause the modified files to carry prominent notices stating
+that you changed the files and the date of any change. 
+
+    b) You must cause any work that you distribute or publish, that in whole
+or in part contains or is derived from the Program or any part
+    thereof, to be licensed as a whole at no charge to all third parties
+under the terms of this License. 
+
+    c) If the modified program normally reads commands interactively when
+run, you must cause it, when started running for such interactive
+    use in the most ordinary way, to print or display an announcement
+including an appropriate copyright notice and a notice that there is no
+    warranty (or else, saying that you provide a warranty) and that users
+may redistribute the program under these conditions, and telling the
+    user how to view a copy of this License. (Exception: if the Program
+itself is interactive but does not normally print such an announcement,
+    your work based on the Program is not required to print an
+announcement.) 
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you
+distribute them as separate works. But when you distribute the same sections
+as part of a whole which is a work based on the Program, the
+distribution of the whole must be on the terms of this License, whose
+permissions for other licensees extend to the entire whole, and thus to each
+and every part regardless of who wrote it. 
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise
+the
+right to control the distribution of derivative or collective works based on
+the Program. 
+
+In addition, mere aggregation of another work not based on the Program with
+the Program (or with a work based on the Program) on a volume
+of a storage or distribution medium does not bring the other work under the
+scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following: 
+
+    a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1
+    and 2 above on a medium customarily used for software interchange; or, 
+
+    b) Accompany it with a written offer, valid for at least three years, to
+give any third party, for a charge no more than your cost of physically
+    performing source distribution, a complete machine-readable copy of the
+corresponding source code, to be distributed under the terms of
+    Sections 1 and 2 above on a medium customarily used for software
+interchange; or, 
+
+    c) Accompany it with the information you received as to the offer to
+distribute corresponding source code. (This alternative is allowed only
+    for noncommercial distribution and only if you received the program in
+object code or executable form with such an offer, in accord with
+    Subsection b above.) 
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed
+(in either source or binary form) with the major components (compiler,
+kernel, and so on) of the operating system on which the executable runs,
+unless that component itself accompanies the executable. 
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along
+with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to
+copy, modify, sublicense or distribute the Program is void, and will
+automatically terminate your rights under this License. However, parties who
+have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full
+compliance. 
+
+5. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute
+the Program or its derivative works. These actions are prohibited by law if
+you do not accept this License. Therefore, by modifying or distributing
+the Program (or any work based on the Program), you indicate your acceptance
+of this License to do so, and all its terms and conditions for
+copying, distributing or modifying the Program or works based on it. 
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms
+and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible
+for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from
+the conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at
+all. For example, if a patent license would not permit royalty-free
+redistribution of the Program by all those who receive copies directly or
+indirectly through you, then the only way you could satisfy both it and
+this License would be to refrain entirely from distribution of the Program. 
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply
+and the section as a whole is intended to apply in other circumstances. 
+
+It is not the purpose of this section to induce you to infringe any patents
+or other property right claims or to contest validity of any such claims;
+this section has the sole purpose of protecting the integrity of the free
+software distribution system, which is implemented by public license
+practices. Many people have made generous contributions to the wide range of
+software distributed through that system in reliance on consistent
+application of that system; it is up to the author/donor to decide if he or
+she is willing to distribute software through any other system and a
+licensee cannot impose that choice. 
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an
+explicit geographical distribution limitation excluding those countries, so
+that distribution is permitted only in or among countries not thus excluded.
+In such case, this License incorporates the limitation as if written in
+the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of
+the General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail
+to address new problems or concerns. 
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free
+Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to
+ask for permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally. 
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE
+EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING
+THE COPYRIGHT HOLDERS
+AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+PROGRAM IS WITH YOU.
+SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+SERVICING, REPAIR OR
+CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER,
+OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS
+PERMITTED ABOVE, BE LIABLE
+TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS
+BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/envy24control/Makefile.am b/envy24control/Makefile.am
new file mode 100644 (file)
index 0000000..8708de1
--- /dev/null
@@ -0,0 +1,9 @@
+bin_PROGRAMS = envy24control
+envy24control_SOURCES = envy24control.c envy24control.h levelmeters.c \
+                        mixer.c patchbay.c hardware.c driverevents.c
+envy24control_LDFLAGS = $(GTK_LIBS)
+EXTRA_DIST = cvscompile
+
+clean:
+       rm -rf .deps *~
+
diff --git a/envy24control/configure.in b/envy24control/configure.in
new file mode 100644 (file)
index 0000000..d274cb5
--- /dev/null
@@ -0,0 +1,11 @@
+AC_INIT(envy24control.c)
+AM_INIT_AUTOMAKE(envy24control, 0.1.0)
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_HEADER_STDC
+AM_PATH_GTK(1.0.1)
+AM_PATH_ALSA(0.6.0)
+CFLAGS="$CFLAGS $GTK_CFLAGS $ALSA_FLAGS"
+LDFLAGS="$LDFLAGS $GTK_LIBS $ALSA_LIBS"
+
+AC_OUTPUT(Makefile)
diff --git a/envy24control/cvscompile b/envy24control/cvscompile
new file mode 100644 (file)
index 0000000..e54e9cd
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+share=/usr/share/automake/missing
+
+aclocal $ACLOCAL_FLAGS
+automake --foreign
+if [ ! -r install-sh ]; then
+  cp $share/install-sh .
+fi
+if [ ! -r mkinstalldirs ]; then
+  cp $share/mkinstalldirs .
+fi
+if [ ! -r missing ]; then
+  cp $share/missing .
+fi
+autoconf
+export CFLAGS='-O2 -Wall -pipe -g'
+echo "CFLAGS=$CFLAGS"
+echo "./configure $@"
+./configure $@
+unset CFLAGS
+make
diff --git a/envy24control/driverevents.c b/envy24control/driverevents.c
new file mode 100644 (file)
index 0000000..88596e7
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************
+   driverevents.c - Events from the driver processing
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+static void control_value(snd_ctl_t *handle, void *private_data, snd_control_id_t *id)
+{
+       if (id->iface == SND_CONTROL_IFACE_PCM) {
+               if (!strcmp(id->name, "Multi Track Route")) {
+                       patchbay_update();
+                       return;
+               }
+               if (!strcmp(id->name, "Multi Track S/PDIF Master")) {
+                       master_clock_update();
+                       return;
+               }
+               if (!strcmp(id->name, "Word Clock Sync")) {
+                       master_clock_update();
+                       return;
+               }
+               if (!strcmp(id->name, "Multi Track Volume Rate")) {
+                       volume_change_rate_update();
+                       return;
+               }
+               if (!strcmp(id->name, "S/PDIF Input Optical")) {
+                       spdif_input_update();
+                       return;
+               }
+               if (!strcmp(id->name, "Delta S/PDIF Output Defaults")) {
+                       spdif_output_update();
+                       return;
+               }
+       }
+       if (id->iface == SND_CONTROL_IFACE_MIXER) {
+               if (!strcmp(id->name, "Multi Playback Volume")) {
+                       mixer_update_stream(id->index + 1, 1, 0);
+                       return;
+               }
+               if (!strcmp(id->name, "Multi Capture Volume")) {
+                       mixer_update_stream(id->index + 11, 1, 0);
+                       return;
+               }       
+               if (!strcmp(id->name, "Multi Playback Switch")) {
+                       mixer_update_stream(id->index + 1, 0, 1);
+                       return;
+               }
+               if (!strcmp(id->name, "Multi Capture Switch")) {
+                       mixer_update_stream(id->index + 11, 0, 1);
+                       return;
+               }
+       }
+}
+
+static snd_ctl_callbacks_t control_callbacks = {
+       private_data: NULL,
+       rebuild: NULL,          /* FIXME!! */
+       value: control_value,
+       change: NULL,
+       add: NULL,
+       remove: NULL,
+       reserved: { NULL, }
+};
+
+void control_input_callback(gpointer data, gint source, GdkInputCondition condition)
+{
+       snd_ctl_read(card_ctl, &control_callbacks);
+}
diff --git a/envy24control/envy24control.c b/envy24control/envy24control.c
new file mode 100644 (file)
index 0000000..a92f3d0
--- /dev/null
@@ -0,0 +1,1132 @@
+/*****************************************************************************
+   envy24control.c - Env24 chipset (ICE1712) control utility
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+int card = 0;
+snd_ctl_t *card_ctl = NULL;
+snd_ctl_hw_info_t hw_info;
+ice1712_eeprom_t card_eeprom;
+
+GtkWidget *window;
+
+GtkWidget *mixer_mix_drawing;
+GtkWidget *mixer_clear_peaks_button;
+GtkWidget *mixer_drawing[20];
+GtkObject *mixer_adj[20][2];
+GtkWidget *mixer_vscale[20][2];
+GtkWidget *mixer_solo_toggle[20][2];
+GtkWidget *mixer_mute_toggle[20][2];
+GtkWidget *mixer_stereo_toggle[20];
+
+GtkWidget *router_radio[10][12];
+
+GtkWidget *hw_master_clock_xtal_radio;
+GtkWidget *hw_master_clock_spdif_radio;
+GtkWidget *hw_master_clock_word_radio;
+GtkWidget *hw_master_clock_status_label;
+
+GtkObject *hw_volume_change_adj;
+GtkWidget *hw_volume_change_spin;
+
+GtkWidget *hw_spdif_profi_nonaudio_radio;
+GtkWidget *hw_spdif_profi_audio_radio;
+
+GtkWidget *hw_profi_stream_stereo_radio;
+GtkWidget *hw_profi_stream_notid_radio;
+
+GtkWidget *hw_profi_emphasis_none_radio;
+GtkWidget *hw_profi_emphasis_5015_radio;
+GtkWidget *hw_profi_emphasis_ccitt_radio;
+GtkWidget *hw_profi_emphasis_notid_radio;
+
+GtkWidget *hw_consumer_copyright_on_radio;
+GtkWidget *hw_consumer_copyright_off_radio;
+
+GtkWidget *hw_consumer_copy_1st_radio;
+GtkWidget *hw_consumer_copy_original_radio;
+
+GtkWidget *hw_consumer_emphasis_none_radio;
+GtkWidget *hw_consumer_emphasis_5015_radio;
+
+GtkWidget *hw_consumer_category_dat_radio;
+GtkWidget *hw_consumer_category_pcm_radio;
+GtkWidget *hw_consumer_category_cd_radio;
+GtkWidget *hw_consumer_category_general_radio;
+
+GtkWidget *hw_spdif_professional_radio;
+GtkWidget *hw_spdif_consumer_radio;
+GtkWidget *hw_spdif_output_notebook;
+
+GtkWidget *hw_spdif_input_coaxial_radio;
+GtkWidget *hw_spdif_input_optical_radio;
+
+
+
+static void create_mixer_frame(GtkWidget *fixed, int stream)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkObject *adj;
+       GtkWidget *vscale;
+       GtkWidget *drawing;
+       GtkWidget *label;
+       GtkWidget *toggle;
+       GtkWidget *hseparator;
+       char str[64], drawname[32];
+
+       if (stream <= 10) {
+               sprintf(str, "PCM Out %i", stream);
+       } else if (stream <= 18) {
+               sprintf(str, "H/W In %i", stream - 10);
+       } else if (stream == 19) {
+               strcpy(str, "S/PDIF In L");
+       } else if (stream == 20) {
+               strcpy(str, "S/PDIF In R");
+       } else {
+               strcpy(str, "???");
+       }
+
+       frame = gtk_frame_new(str);
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 2 + (stream - 1) * 102, 2);
+       gtk_widget_set_uposition(frame, 2 + (stream - 1) * 102, 2);
+       gtk_widget_set_usize(frame, 98, 288);
+       gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       adj = gtk_adjustment_new(96, 0, 96, 1, 16, 0);
+       mixer_adj[stream-1][0] = adj;
+       vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
+       mixer_vscale[stream-1][0] = vscale;
+        gtk_widget_show(vscale);
+       gtk_fixed_put(GTK_FIXED(fixed1), vscale, 8, 8);
+       gtk_widget_set_uposition(vscale, 7, 8);
+       gtk_widget_set_usize(vscale, 18, 146);  
+       gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
+       gtk_scale_set_digits(GTK_SCALE(vscale), 0);
+       gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
+                          GTK_SIGNAL_FUNC(mixer_adjust), (gpointer)((stream << 16) + 0));
+
+       drawing = gtk_drawing_area_new();
+       mixer_drawing[stream-1] = drawing;
+       sprintf(drawname, "Mixer%i", stream);
+       gtk_widget_set_name(drawing, drawname);
+       gtk_widget_show(drawing);
+       gtk_signal_connect(GTK_OBJECT(drawing), "expose_event",
+                          (GtkSignalFunc)level_meters_expose_event, NULL);
+       gtk_signal_connect(GTK_OBJECT(drawing), "configure_event",
+                          (GtkSignalFunc)level_meters_configure_event, NULL);
+       gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
+       gtk_fixed_put(GTK_FIXED(fixed1), drawing, 24, 9);
+       gtk_widget_set_uposition(drawing, 24, 9);
+       gtk_widget_set_usize(drawing, 45, 130); 
+
+       adj = gtk_adjustment_new(96, 0, 96, 1, 16, 0);
+       mixer_adj[stream-1][1] = adj;
+       vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
+       mixer_vscale[stream-1][1] = vscale;
+        gtk_widget_show(vscale);
+       gtk_fixed_put(GTK_FIXED(fixed1), vscale, 70, 8);
+       gtk_widget_set_uposition(vscale, 69, 8);
+       gtk_widget_set_usize(vscale, 18, 146);  
+       gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
+       gtk_scale_set_digits(GTK_SCALE(vscale), 0);
+       gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
+                          GTK_SIGNAL_FUNC(mixer_adjust), (gpointer)((stream << 16) + 1));
+
+        label = gtk_label_new("Left");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed1), label, 0, 160);
+       gtk_widget_set_uposition(label, 0, 160);
+       gtk_widget_set_usize(label, 41, 16);    
+
+        label = gtk_label_new("Right");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed1), label, 45, 160);
+       gtk_widget_set_uposition(label, 45, 160);
+       gtk_widget_set_usize(label, 41, 16);
+
+       toggle = gtk_toggle_button_new_with_label("On");
+       mixer_solo_toggle[stream-1][0] = toggle;
+       gtk_widget_show(toggle);
+       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 8, 176);
+       gtk_widget_set_uposition(toggle, 8, 176);
+       gtk_widget_set_usize(toggle, 36, 22);   
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), FALSE);
+       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
+                          (GtkSignalFunc)mixer_toggled_solo, (gpointer)((stream << 16) + 0));
+       
+       toggle = gtk_toggle_button_new_with_label("On");
+       mixer_solo_toggle[stream-1][1] = toggle;
+       gtk_widget_show(toggle);
+       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 48, 176);
+       gtk_widget_set_uposition(toggle, 48, 176);
+       gtk_widget_set_usize(toggle, 36, 22);   
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), FALSE);
+       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
+                          (GtkSignalFunc)mixer_toggled_solo, (gpointer)((stream << 16) + 1));
+       
+       toggle = gtk_toggle_button_new_with_label("Mute");
+       mixer_mute_toggle[stream-1][0] = toggle;
+       gtk_widget_show(toggle);
+       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 8, 202);
+       gtk_widget_set_uposition(toggle, 8, 202);
+       gtk_widget_set_usize(toggle, 36, 22);   
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE);
+       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
+                          (GtkSignalFunc)mixer_toggled_mute, (gpointer)((stream << 16) + 0));
+       
+       toggle = gtk_toggle_button_new_with_label("Mute");
+       mixer_mute_toggle[stream-1][1] = toggle;
+       gtk_widget_show(toggle);
+       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 48, 202);
+       gtk_widget_set_uposition(toggle, 48, 202);
+       gtk_widget_set_usize(toggle, 36, 22);   
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE);
+       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
+                          (GtkSignalFunc)mixer_toggled_mute, (gpointer)((stream << 16) + 1));
+       
+       hseparator = gtk_hseparator_new();
+       gtk_widget_show(hseparator);
+       gtk_fixed_put(GTK_FIXED(fixed1), hseparator, 0, 222);
+       gtk_widget_set_uposition(hseparator, 0, 222);
+       gtk_widget_set_usize(hseparator, 92, 16);
+
+       toggle = gtk_toggle_button_new_with_label("Stereo Gang");
+       mixer_stereo_toggle[stream-1] = toggle;
+       gtk_widget_show(toggle);
+       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 3, 235);
+       gtk_widget_set_uposition(toggle, 3, 235);
+       gtk_widget_set_usize(toggle, 88, 32);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE);
+}
+
+static void create_mixer(GtkWidget *main, GtkWidget *notebook, int page)
+{
+       GtkWidget *label;
+       GtkWidget *hpaned;
+       GtkWidget *frame;
+       GtkWidget *fixed;
+       GtkWidget *drawing;
+       GtkWidget *hseparator;
+       GtkWidget *button;
+       GtkWidget *scrollwin;
+       GtkWidget *viewport;
+       int stream;
+
+       hpaned = gtk_hpaned_new();
+       gtk_widget_show(hpaned);
+       gtk_container_add(GTK_CONTAINER(notebook), hpaned);
+       gtk_paned_set_gutter_size(GTK_PANED(hpaned), 4);
+       gtk_paned_set_position(GTK_PANED(hpaned), 108);
+        label = gtk_label_new("Monitor Mixer");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+
+       /* create digital mixer frame */
+       frame = gtk_frame_new("Digital Mixer");
+       gtk_widget_show(frame);
+       gtk_container_add(GTK_CONTAINER(hpaned), frame);
+       gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+
+       /* create controls in the digital mixer frame */
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(frame), fixed); 
+
+       drawing = gtk_drawing_area_new();
+       mixer_mix_drawing = drawing;
+       gtk_widget_set_name(drawing, "DigitalMixer");
+       gtk_signal_connect(GTK_OBJECT(drawing), "expose_event",
+                          (GtkSignalFunc)level_meters_expose_event, NULL);
+       gtk_signal_connect(GTK_OBJECT(drawing), "configure_event",
+                          (GtkSignalFunc)level_meters_configure_event, NULL);
+       gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
+       gtk_widget_show(drawing);
+       gtk_fixed_put(GTK_FIXED(fixed), drawing, 4, 2);
+       gtk_widget_set_uposition(drawing, 4, 2);
+       gtk_widget_set_usize(drawing, 98, 226); 
+
+        label = gtk_label_new("Left");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed), label, 0, 232);
+       gtk_widget_set_uposition(label, 0, 232);
+       gtk_widget_set_usize(label, 34, 16);    
+
+        label = gtk_label_new("Right");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed), label, 60, 232);
+       gtk_widget_set_uposition(label, 60, 232);
+       gtk_widget_set_usize(label, 34, 16);
+
+       hseparator = gtk_hseparator_new();
+       gtk_widget_show(hseparator);
+       gtk_fixed_put(GTK_FIXED(fixed), hseparator, 0, 244);
+       gtk_widget_set_uposition(hseparator, 0, 244);
+       gtk_widget_set_usize(hseparator, 104, 16);
+
+       button = gtk_button_new_with_label("Reset Peaks");
+       mixer_clear_peaks_button = button;
+       gtk_widget_show(button);
+       gtk_fixed_put(GTK_FIXED(fixed), button, 3, 256);
+       gtk_widget_set_uposition(button, 3, 256);
+       gtk_widget_set_usize(button, 98, 35);   
+       gtk_signal_connect(GTK_OBJECT(button), "clicked",
+                          GTK_SIGNAL_FUNC(level_meters_reset_peaks), NULL);
+
+       /* build scrolling area */
+       scrollwin = gtk_scrolled_window_new(NULL, NULL);
+       gtk_widget_show(scrollwin);
+       gtk_container_add(GTK_CONTAINER(hpaned), scrollwin);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
+
+       viewport = gtk_viewport_new(NULL, NULL);
+       gtk_widget_show(viewport);
+       gtk_container_add(GTK_CONTAINER(scrollwin), viewport);
+
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(viewport), fixed);      
+       
+       for (stream = 1; stream <= 20; stream++)
+               create_mixer_frame(fixed, stream);
+}
+
+static void create_router_frame(GtkWidget *fixed, int stream)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GtkWidget *hseparator;
+       GSList *group = NULL;
+       char str[64], str1[64];
+       int idx;
+       static char *table[10] = {
+               "S/PDIF In L",
+               "S/PDIF In R",
+               "H/W In 1",
+               "H/W In 2",
+               "H/W In 3",
+               "H/W In 4",
+               "H/W In 5",
+               "H/W In 6",
+               "H/W In 7",
+               "H/W In 8"
+       };
+
+       if (stream <= 8) {
+               sprintf(str, "H/W Out %i (%s)", stream, stream & 1 ? "L" : "R");
+       } else if (stream == 9) {
+               strcpy(str, "S/PDIF Out L");
+       } else if (stream == 10) {
+               strcpy(str, "S/PDIF Out R");
+       } else {
+               strcpy(str, "???");
+       }
+       sprintf(str1, "PCM Out %i", stream);
+
+       frame = gtk_frame_new(str);
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 2 + (stream - 1) * 101, 2);
+       gtk_widget_set_uposition(frame, 2 + (stream - 1) * 101, 2);
+       gtk_widget_set_usize(frame, 98, 284);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, str1);
+       router_radio[stream-1][0] = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 0, 0);
+       gtk_widget_set_uposition(radio, 0, 0);
+       gtk_widget_set_usize(radio, 93, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)patchbay_toggled, (gpointer)((stream << 16) + 0));
+
+       hseparator = gtk_hseparator_new();
+       gtk_widget_show(hseparator);
+       gtk_fixed_put(GTK_FIXED(fixed1), hseparator, 0, 21);
+       gtk_widget_set_uposition(hseparator, 0, 21);
+       gtk_widget_set_usize(hseparator, 94, 16);
+
+       if (stream == 1 || stream == 2 || stream == 9 || stream == 10) {
+               radio = gtk_radio_button_new_with_label(group, stream & 1 ? "Digital Mix L" : "Digital Mix R");
+               router_radio[stream-1][1] = radio;
+               group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+               gtk_widget_show(radio);
+               gtk_fixed_put(GTK_FIXED(fixed1), radio, 0, 32);
+               gtk_widget_set_uposition(radio, 0, 32);
+               gtk_widget_set_usize(radio, 93, 24);
+               gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                                  (GtkSignalFunc)patchbay_toggled, (gpointer)((stream << 16) + 1));
+       }
+
+       hseparator = gtk_hseparator_new();
+       gtk_widget_show(hseparator);
+       gtk_fixed_put(GTK_FIXED(fixed1), hseparator, 0, 52);
+       gtk_widget_set_uposition(hseparator, 0, 52);
+       gtk_widget_set_usize(hseparator, 94, 16);
+
+       for (idx = 0; idx < 10; idx++) {
+               radio = gtk_radio_button_new_with_label(group, table[idx]);
+               router_radio[stream-1][2+idx] = radio;
+               group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+               gtk_widget_show(radio);
+               gtk_fixed_put(GTK_FIXED(fixed1), radio, 0, 64 + (idx * 20));
+               gtk_widget_set_uposition(radio, 0, 64 + (idx * 20));
+               gtk_widget_set_usize(radio, 93, 24);
+               gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                                  (GtkSignalFunc)patchbay_toggled, (gpointer)((stream << 16) + 2 + idx));
+       }
+}
+
+static void create_router(GtkWidget *main, GtkWidget *notebook, int page)
+{
+       GtkWidget *label;
+       GtkWidget *scrollwin;
+       GtkWidget *viewport;
+       GtkWidget *fixed;
+       int stream;
+
+       scrollwin = gtk_scrolled_window_new(NULL, NULL);
+       gtk_widget_show(scrollwin);
+       gtk_container_add(GTK_CONTAINER(notebook), scrollwin);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
+        label = gtk_label_new("Patchbay / Router");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+       viewport = gtk_viewport_new(NULL, NULL);
+       gtk_widget_show(viewport);
+       gtk_container_add(GTK_CONTAINER(scrollwin), viewport);
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(viewport), fixed);      
+
+       for (stream = 1; stream <= 10; stream++)
+               create_router_frame(fixed, stream);
+}
+
+static void create_master_clock(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GtkWidget *viewport;
+       GtkWidget *fixed2;
+       GtkWidget *label;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Master Clock");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 8, 8);
+       gtk_widget_set_uposition(frame, 8, 8);
+       gtk_widget_set_usize(frame, 111, 125);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "Internal Xtal");
+       hw_master_clock_xtal_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 0);
+       gtk_widget_set_uposition(radio, 8, 0);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)master_clock_toggled, (gpointer)"Xtal");
+
+       radio = gtk_radio_button_new_with_label(group, "S/PDIF In");
+       hw_master_clock_spdif_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 24);
+       gtk_widget_set_uposition(radio, 8, 24);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)master_clock_toggled, (gpointer)"SPDIF");
+
+       if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010)
+               return;
+
+       radio = gtk_radio_button_new_with_label(group, "Word Clock");
+       hw_master_clock_word_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 48);
+       gtk_widget_set_uposition(radio, 8, 48);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)master_clock_toggled, (gpointer)"WordClock");
+
+       viewport = gtk_viewport_new(NULL, NULL);
+       gtk_widget_show(viewport);
+       gtk_fixed_put(GTK_FIXED(fixed1), viewport, 9, 75);
+       gtk_widget_set_uposition(viewport, 9, 75);
+       gtk_widget_set_usize(viewport, 90, 26);
+
+       fixed2 = gtk_fixed_new();
+       gtk_widget_show(fixed2);
+       gtk_container_add(GTK_CONTAINER(viewport), fixed2);     
+
+        label = gtk_label_new("Locked");
+        hw_master_clock_status_label = label;
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed2), label, 0, 3);
+       gtk_widget_set_uposition(label, 0, 3);
+       gtk_widget_set_usize(label, 86, 16);
+}
+
+static void create_volume_change(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkObject *adj;
+       GtkWidget *spin;
+       GtkWidget *label;
+
+       frame = gtk_frame_new("Volume Change");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 8, 144);
+       gtk_widget_set_uposition(frame, 8, 144);
+       gtk_widget_set_usize(frame, 111, 132);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       adj = gtk_adjustment_new(16, 0, 255, 1, 10, 10);
+       hw_volume_change_adj = adj;
+       spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
+       hw_volume_change_spin = spin;
+       gtk_widget_show(spin);
+       gtk_fixed_put(GTK_FIXED(fixed1), spin, 48, 40);
+       gtk_widget_set_uposition(spin, 48, 40);
+       gtk_widget_set_usize(spin, 53, 22);
+       gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin), TRUE);
+       gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
+                          GTK_SIGNAL_FUNC(volume_change_rate_adj), NULL);
+       
+        label = gtk_label_new("Rate:");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed1), label, 0, 3);
+       gtk_widget_set_uposition(label, 0, 42);
+       gtk_widget_set_usize(label, 41, 16);
+}
+
+static void create_spdif_output_settings_profi_data(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Data Mode");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 10, 10);
+       gtk_widget_set_uposition(frame, 10, 10);
+       gtk_widget_set_usize(frame, 100, 81);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "Non-audio");
+       hw_spdif_profi_nonaudio_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 84, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_data_toggled, (gpointer)"Non-audio");
+
+       radio = gtk_radio_button_new_with_label(group, "Audio");
+       hw_spdif_profi_audio_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 84, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_data_toggled, (gpointer)"Audio");
+}
+
+static void create_spdif_output_settings_profi_stream(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Stream");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 120, 10);
+       gtk_widget_set_uposition(frame, 120, 10);
+       gtk_widget_set_usize(frame, 116, 81);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "Stereophonic");
+       hw_profi_stream_stereo_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 96, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_stream_toggled, (gpointer)"Stereo");
+
+       radio = gtk_radio_button_new_with_label(group, "Not indicated");
+       hw_profi_stream_notid_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 96, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_stream_toggled, (gpointer)"NOTID");
+}
+
+static void create_spdif_output_settings_profi_emphasis(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Emphasis");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 10, 10);
+       gtk_widget_set_uposition(frame, 246, 10);
+       gtk_widget_set_usize(frame, 114, 131);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "No emphasis");
+       hw_profi_emphasis_none_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 94, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_emphasis_toggled, (gpointer)"No");
+
+       radio = gtk_radio_button_new_with_label(group, "50/15us");
+       hw_profi_emphasis_5015_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 94, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_emphasis_toggled, (gpointer)"5015");
+
+       radio = gtk_radio_button_new_with_label(group, "CCITT J.17");
+       hw_profi_emphasis_ccitt_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 56);
+       gtk_widget_set_uposition(radio, 8, 56);
+       gtk_widget_set_usize(radio, 94, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_emphasis_toggled, (gpointer)"CCITT");
+
+       radio = gtk_radio_button_new_with_label(group, "Not indicated");
+       hw_profi_emphasis_notid_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 80);
+       gtk_widget_set_uposition(radio, 8, 80);
+       gtk_widget_set_usize(radio, 94, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)profi_emphasis_toggled, (gpointer)"NOTID");
+}
+
+static void create_spdif_output_settings_profi(GtkWidget *notebook, int page)
+{
+       GtkWidget *fixed;
+       GtkWidget *label;
+
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(notebook), fixed);
+        label = gtk_label_new("Professional");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+
+       create_spdif_output_settings_profi_data(fixed);
+       create_spdif_output_settings_profi_stream(fixed);
+       create_spdif_output_settings_profi_emphasis(fixed);
+}
+
+static void create_spdif_output_settings_consumer_copyright(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Copyright");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 10, 10);
+       gtk_widget_set_uposition(frame, 10, 10);
+       gtk_widget_set_usize(frame, 124, 79);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);
+
+       radio = gtk_radio_button_new_with_label(group, "Copyrighted");
+       hw_consumer_copyright_on_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 106, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_copyright_toggled, (gpointer)"Copyright");
+
+       radio = gtk_radio_button_new_with_label(group, "Copy permitted");
+       hw_consumer_copyright_off_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 106, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_copyright_toggled, (gpointer)"Permitted");
+}
+
+static void create_spdif_output_settings_consumer_copy(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Copy");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 10, 96);
+       gtk_widget_set_uposition(frame, 10, 96);
+       gtk_widget_set_usize(frame, 124, 79);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);
+
+       radio = gtk_radio_button_new_with_label(group, "1-st generation");
+       hw_consumer_copy_1st_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 106, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_copy_toggled, (gpointer)"1st");
+
+       radio = gtk_radio_button_new_with_label(group, "Original");
+       hw_consumer_copy_original_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 106, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_copy_toggled, (gpointer)"Original");
+}
+
+static void create_spdif_output_settings_consumer_emphasis(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Emphasis");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 144, 10);
+       gtk_widget_set_uposition(frame, 144, 10);
+       gtk_widget_set_usize(frame, 130, 80);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);
+
+       radio = gtk_radio_button_new_with_label(group, "No emphasis");
+       hw_consumer_emphasis_none_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_emphasis_toggled, (gpointer)"No");
+
+       radio = gtk_radio_button_new_with_label(group, "50/15us");
+       hw_consumer_emphasis_5015_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_emphasis_toggled, (gpointer)"5015");
+}
+
+static void create_spdif_output_settings_consumer_category(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("Category");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 283, 10);
+       gtk_widget_set_uposition(frame, 283, 10);
+       gtk_widget_set_usize(frame, 130, 126);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "DAT");
+       hw_consumer_category_dat_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 102, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_category_toggled, (gpointer)"DAT");
+
+       radio = gtk_radio_button_new_with_label(group, "PCM encoder");
+       hw_consumer_category_pcm_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 102, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_category_toggled, (gpointer)"PCM");
+
+       radio = gtk_radio_button_new_with_label(group, "CD (ICE-908)");
+       hw_consumer_category_cd_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 56);
+       gtk_widget_set_uposition(radio, 8, 56);
+       gtk_widget_set_usize(radio, 102, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_category_toggled, (gpointer)"CD");
+
+       radio = gtk_radio_button_new_with_label(group, "General");
+       hw_consumer_category_general_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 80);
+       gtk_widget_set_uposition(radio, 8, 80);
+       gtk_widget_set_usize(radio, 102, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)consumer_category_toggled, (gpointer)"General");
+}
+
+static void create_spdif_output_settings_consumer(GtkWidget *notebook, int page)
+{
+       GtkWidget *fixed;
+       GtkWidget *label;
+
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(notebook), fixed);
+       label = gtk_label_new("Consumer");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+
+       create_spdif_output_settings_consumer_copyright(fixed);
+       create_spdif_output_settings_consumer_copy(fixed);
+       create_spdif_output_settings_consumer_emphasis(fixed);
+       create_spdif_output_settings_consumer_category(fixed);
+}
+
+static void create_spdif_output_settings(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GtkWidget *notebook;
+       GSList *group = NULL;
+
+       frame = gtk_frame_new("S/PDIF Output Settings");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 128, 8);
+       gtk_widget_set_uposition(frame, 128, 8);
+       gtk_widget_set_usize(frame, 442, 268);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "Professional");
+       hw_spdif_professional_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 24, 4);
+       gtk_widget_set_uposition(radio, 24, 4);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)spdif_output_toggled, (gpointer)"Professional");
+
+       radio = gtk_radio_button_new_with_label(group, "Consumer");
+       hw_spdif_consumer_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 128, 4);
+       gtk_widget_set_uposition(radio, 128, 4);
+       gtk_widget_set_usize(radio, 92, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)spdif_output_toggled, (gpointer)"Consumer");
+
+       notebook = gtk_notebook_new();
+       hw_spdif_output_notebook = notebook;
+       gtk_widget_show(notebook);
+       gtk_fixed_put(GTK_FIXED(fixed1), notebook, 5, 31);
+       gtk_widget_set_uposition(notebook, 5, 31);
+       gtk_widget_set_usize(notebook, 427, 215);
+
+       create_spdif_output_settings_profi(notebook, 0);
+       create_spdif_output_settings_consumer(notebook, 1);
+}
+
+static void create_spdif_input_select(GtkWidget *fixed)
+{
+       GtkWidget *frame;
+       GtkWidget *fixed1;
+       GtkWidget *radio;
+       GSList *group = NULL;
+       int hide = 1;
+
+       if (card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTADIO2496)
+               hide = 0;
+
+       frame = gtk_frame_new("S/PDIF Input");
+       gtk_widget_show(frame);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 579, 8);
+       gtk_widget_set_uposition(frame, 579, 8);
+       gtk_widget_set_usize(frame, 98, 79);
+
+       fixed1 = gtk_fixed_new();
+       gtk_widget_show(fixed1);
+       gtk_container_add(GTK_CONTAINER(frame), fixed1);        
+
+       radio = gtk_radio_button_new_with_label(group, "Coaxial");
+       hw_spdif_input_coaxial_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 8);
+       gtk_widget_set_uposition(radio, 8, 8);
+       gtk_widget_set_usize(radio, 82, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)spdif_input_toggled, (gpointer)"Coaxial");
+
+       radio = gtk_radio_button_new_with_label(group, "Optical");
+       hw_spdif_input_optical_radio = radio;
+       group = gtk_radio_button_group(GTK_RADIO_BUTTON(radio));
+       gtk_widget_show(radio);
+       gtk_fixed_put(GTK_FIXED(fixed1), radio, 8, 32);
+       gtk_widget_set_uposition(radio, 8, 32);
+       gtk_widget_set_usize(radio, 82, 24);
+       gtk_signal_connect(GTK_OBJECT(radio), "toggled",
+                          (GtkSignalFunc)spdif_input_toggled, (gpointer)"Optical");
+
+       if (hide)
+               gtk_widget_hide_all(frame);
+}
+
+static void create_hardware(GtkWidget *main, GtkWidget *notebook, int page)
+{
+       GtkWidget *label;
+       GtkWidget *fixed;
+
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(notebook), fixed);
+        label = gtk_label_new("Hardware Settings");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+
+       create_master_clock(fixed);
+       create_volume_change(fixed);
+       create_spdif_output_settings(fixed);
+       create_spdif_input_select(fixed);
+}
+
+static void create_about(GtkWidget *main, GtkWidget *notebook, int page)
+{
+       GtkWidget *label;
+       GtkWidget *fixed;
+
+       fixed = gtk_fixed_new();
+       gtk_widget_show(fixed);
+       gtk_container_add(GTK_CONTAINER(notebook), fixed);
+        label = gtk_label_new("About");
+        gtk_widget_show(label);
+       gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), label);
+
+       /* create first line */
+       label = gtk_label_new("Envy24 Control Utility " VERSION);
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed), label, 0, 72);
+       gtk_widget_set_uposition(label, 0, 72);
+       gtk_widget_set_usize(label, 736, 16);
+
+       /* create second line */
+       label = gtk_label_new("A GTK Tool for Envy24 PCI Audio Chip");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed), label, 0, 104);
+       gtk_widget_set_uposition(label, 0, 104);
+       gtk_widget_set_usize(label, 736, 16);
+
+       /* create third line */
+       label = gtk_label_new("Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>");
+        gtk_widget_show(label);
+       gtk_fixed_put(GTK_FIXED(fixed), label, 0, 152);
+       gtk_widget_set_uposition(label, 0, 152);
+       gtk_widget_set_usize(label, 736, 16);
+}
+
+int main(int argc, char **argv)
+{
+        GtkWidget *notebook;
+        char name[32], title[128];
+       int err;
+       unsigned int cards_mask;
+       snd_control_t ctl;
+       // snd_mixer_filter_t filter;
+
+       /* Go through gtk initialization */
+        gtk_init(&argc, &argv);
+
+       card = snd_defaults_card();
+       cards_mask = snd_cards_mask();
+       
+       while (1) {
+               sprintf(name, "envy24control%d", card);
+               if ((err = snd_ctl_hw_open(&card_ctl, name, card)) < 0) {
+                       fprintf(stderr, "snd_ctl_open: %s\n", snd_strerror(err));
+                       exit(EXIT_FAILURE);
+               }
+               if ((err = snd_ctl_hw_info(card_ctl, &hw_info)) < 0) {
+                       fprintf(stderr, "snd_ctl_hw_info: %s\n", snd_strerror(err));
+                       exit(EXIT_FAILURE);
+               }
+               if (hw_info.type == SND_CARD_TYPE_ICE1712)
+                       break;
+               snd_ctl_close(card_ctl);
+               card_ctl = NULL;
+               cards_mask &= ~(1 << card);
+               for (card = 0; card < 32; card++)
+                       if ((1 << card) & cards_mask)
+                               break;
+               if (card >= 32)
+                       break;
+       }
+       if (card_ctl == NULL) {
+               fprintf(stderr, "Unable to find ICE1712 soundcard...\n");
+               exit(EXIT_FAILURE);
+       }
+
+#if 0
+       memset(&filter, 0, sizeof(filter));
+       snd_mixer_set_bit(filter.read_cmds, SND_MIXER_READ_ELEMENT_VALUE, 1);
+       if ((err = snd_mixer_put_filter(card_mixer, &filter)) < 0) {
+               fprintf(stderr, "snd_mixer_set_filter: %s\n", snd_strerror(err));
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+       memset(&ctl, 0, sizeof(ctl));
+       ctl.id.iface = SND_CONTROL_IFACE_CARD;
+       strcpy(ctl.id.name, "ICE1712 EEPROM");
+       if ((err = snd_ctl_cread(card_ctl, &ctl)) < 0) {
+               fprintf(stderr, "Unable to read EEPROM contents: %s\n", snd_strerror(err));
+               exit(EXIT_FAILURE);
+       }
+       memcpy(&card_eeprom, ctl.value.bytes.data, 32);
+
+       /* Initialize code */
+       level_meters_init();
+       patchbay_init();
+       hardware_init();
+
+        /* Make the title */
+        sprintf(title, "Envy24 Control Utility %s (%s)", VERSION, hw_info.longname);
+
+        /* Create the main window */
+        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+        gtk_window_set_title(GTK_WINDOW(window), title);
+        gtk_signal_connect(GTK_OBJECT (window), "delete_event", 
+                           (GtkSignalFunc) gtk_main_quit, NULL);
+        signal(SIGINT, (void *)gtk_main_quit);
+        gtk_widget_set_usize(window, 740, 340);
+        gtk_window_set_policy(GTK_WINDOW (window), FALSE, FALSE, FALSE);
+        gtk_widget_realize(window);
+
+        /* Create the notebook */
+        notebook = gtk_notebook_new();
+        gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
+        gtk_widget_show(notebook);
+       gtk_container_add(GTK_CONTAINER(window), notebook);
+
+       create_mixer(window, notebook, 0);
+       create_router(window, notebook, 1);
+       create_hardware(window, notebook, 2);
+       create_about(window, notebook, 3);
+
+       gdk_input_add(snd_ctl_poll_descriptor(card_ctl),
+                     GDK_INPUT_READ,
+                     control_input_callback,
+                     NULL);
+       gtk_timeout_add(40, level_meters_timeout_callback, NULL);
+       gtk_timeout_add(100, master_clock_status_timeout_callback, NULL);
+
+       level_meters_postinit();
+       mixer_postinit();
+       patchbay_postinit();
+       hardware_postinit();
+
+       gtk_widget_show(window);
+       gtk_main();
+
+       snd_ctl_close(card_ctl);
+
+       return EXIT_SUCCESS;
+}
diff --git a/envy24control/envy24control.h b/envy24control/envy24control.h
new file mode 100644 (file)
index 0000000..03c8b49
--- /dev/null
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include <sys/asoundlib.h>
+
+#define ICE1712_SUBDEVICE_DELTA1010    0x121430d6
+#define ICE1712_SUBDEVICE_DELTADIO2496 0x121431d6
+#define ICE1712_SUBDEVICE_DELTA66      0x121432d6
+#define ICE1712_SUBDEVICE_DELTA44      0x121433d6
+
+typedef struct {
+       unsigned int subvendor; /* PCI[2c-2f] */
+       unsigned char size;     /* size of EEPROM image in bytes */
+       unsigned char version;  /* must be 1 */
+       unsigned char codec;    /* codec configuration PCI[60] */
+       unsigned char aclink;   /* ACLink configuration PCI[61] */
+       unsigned char i2sID;    /* PCI[62] */
+       unsigned char spdif;    /* S/PDIF configuration PCI[63] */
+       unsigned char gpiomask; /* GPIO initial mask, 0 = write, 1 = don't */
+       unsigned char gpiostate; /* GPIO initial state */
+       unsigned char gpiodir;  /* GPIO direction state */
+       unsigned short ac97main;
+       unsigned short ac97pcm;
+       unsigned short ac97rec;
+       unsigned char ac97recsrc;
+       unsigned char dacID[4]; /* I2S IDs for DACs */
+       unsigned char adcID[4]; /* I2S IDs for ADCs */
+       unsigned char extra[4];
+} ice1712_eeprom_t;
+
+extern snd_ctl_t *card_ctl;
+extern ice1712_eeprom_t card_eeprom;
+
+extern GtkWidget *mixer_mix_drawing;
+extern GtkWidget *mixer_clear_peaks_button;
+extern GtkWidget *mixer_drawing[20];
+extern GtkObject *mixer_adj[20][2];
+extern GtkWidget *mixer_vscale[20][2];
+extern GtkWidget *mixer_solo_toggle[20][2];
+extern GtkWidget *mixer_mute_toggle[20][2];
+extern GtkWidget *mixer_stereo_toggle[20];
+
+extern GtkWidget *router_radio[10][12];
+
+extern GtkWidget *hw_master_clock_xtal_radio;
+extern GtkWidget *hw_master_clock_spdif_radio;
+extern GtkWidget *hw_master_clock_word_radio;
+extern GtkWidget *hw_master_clock_status_label;
+
+extern GtkObject *hw_volume_change_adj;
+extern GtkWidget *hw_volume_change_spin;
+
+extern GtkWidget *hw_spdif_profi_nonaudio_radio;
+extern GtkWidget *hw_spdif_profi_audio_radio;
+
+extern GtkWidget *hw_profi_stream_stereo_radio;
+extern GtkWidget *hw_profi_stream_notid_radio;
+
+extern GtkWidget *hw_profi_emphasis_none_radio;
+extern GtkWidget *hw_profi_emphasis_5015_radio;
+extern GtkWidget *hw_profi_emphasis_ccitt_radio;
+extern GtkWidget *hw_profi_emphasis_notid_radio;
+
+extern GtkWidget *hw_consumer_copyright_on_radio;
+extern GtkWidget *hw_consumer_copyright_off_radio;
+
+extern GtkWidget *hw_consumer_copy_1st_radio;
+extern GtkWidget *hw_consumer_copy_original_radio;
+
+extern GtkWidget *hw_consumer_emphasis_none_radio;
+extern GtkWidget *hw_consumer_emphasis_5015_radio;
+
+extern GtkWidget *hw_consumer_category_dat_radio;
+extern GtkWidget *hw_consumer_category_pcm_radio;
+extern GtkWidget *hw_consumer_category_cd_radio;
+extern GtkWidget *hw_consumer_category_general_radio;
+
+extern GtkWidget *hw_spdif_professional_radio;
+extern GtkWidget *hw_spdif_consumer_radio;
+extern GtkWidget *hw_spdif_output_notebook;
+
+extern GtkWidget *hw_spdif_input_coaxial_radio;
+extern GtkWidget *hw_spdif_input_optical_radio;
+
+
+gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event);
+gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event);
+gint level_meters_timeout_callback(gpointer data);
+void level_meters_reset_peaks(GtkButton *button, gpointer data);
+void level_meters_init(void);
+void level_meters_postinit(void);
+
+void mixer_update_stream(int stream, int vol_flag, int sw_flag);
+void mixer_toggled_solo(GtkWidget *togglebutton, gpointer data);
+void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data);
+void mixer_adjust(GtkAdjustment *adj, gpointer data);
+void mixer_postinit(void);
+
+void patchbay_update(void);
+void patchbay_toggled(GtkWidget *togglebutton, gpointer data);
+void patchbay_init(void);
+void patchbay_postinit(void);
+
+void master_clock_update(void);
+void master_clock_toggled(GtkWidget *togglebutton, gpointer data);
+gint master_clock_status_timeout_callback(gpointer data);
+void volume_change_rate_update(void);
+void volume_change_rate_adj(GtkAdjustment *adj, gpointer data);
+void profi_data_toggled(GtkWidget *togglebutton, gpointer data);
+void profi_stream_toggled(GtkWidget *togglebutton, gpointer data);
+void profi_emphasis_toggled(GtkWidget *togglebutton, gpointer data);
+void consumer_copyright_toggled(GtkWidget *togglebutton, gpointer data);
+void consumer_copy_toggled(GtkWidget *togglebutton, gpointer data);
+void consumer_emphasis_toggled(GtkWidget *togglebutton, gpointer data);
+void consumer_category_toggled(GtkWidget *togglebutton, gpointer data);
+void spdif_output_update(void);
+void spdif_output_toggled(GtkWidget *togglebutton, gpointer data);
+void spdif_input_update(void);
+void spdif_input_toggled(GtkWidget *togglebutton, gpointer data);
+void hardware_init(void);
+void hardware_postinit(void);
+
+void control_input_callback(gpointer data, gint source, GdkInputCondition condition);
+void mixer_input_callback(gpointer data, gint source, GdkInputCondition condition);
diff --git a/envy24control/hardware.c b/envy24control/hardware.c
new file mode 100644 (file)
index 0000000..3884f74
--- /dev/null
@@ -0,0 +1,415 @@
+/*****************************************************************************
+   hardware.c - Hardware Settings
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+static snd_control_t spdif_master;
+static snd_control_t word_clock_sync;
+static snd_control_t volume_rate;
+static snd_control_t spdif_input;
+static snd_control_t spdif_output;
+
+#define toggle_set(widget, state) \
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
+
+static int is_active(GtkWidget *widget)
+{
+       return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
+}
+
+void master_clock_update(void)
+{
+       int err;
+       
+       if ((err = snd_ctl_cread(card_ctl, &spdif_master)) < 0)
+               g_print("Unable to read S/PDIF master state: %s\n", snd_strerror(err));
+       if (card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010) {
+               if ((err = snd_ctl_cread(card_ctl, &word_clock_sync)) < 0)
+                       g_print("Unable to read word clock sync selection: %s\n", snd_strerror(err));
+       }
+       if (spdif_master.value.integer.value[0]) {
+               if (word_clock_sync.value.integer.value[0]) {
+                       toggle_set(hw_master_clock_word_radio, TRUE);
+               } else {
+                       toggle_set(hw_master_clock_spdif_radio, TRUE);
+               }
+       } else {
+               toggle_set(hw_master_clock_xtal_radio, TRUE);
+       }
+       master_clock_status_timeout_callback(NULL);
+}
+
+static void master_clock_spdif_master(int on)
+{
+       int err;
+
+       spdif_master.value.integer.value[0] = on ? 1 : 0;
+       if ((err = snd_ctl_cwrite(card_ctl, &spdif_master)) < 0)
+               g_print("Unable to write S/PDIF master state: %s\n", snd_strerror(err));
+}
+
+static void master_clock_word_select(int on)
+{
+       int err;
+
+       if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010)
+               return;
+       word_clock_sync.value.integer.value[0] = on ? 1 : 0;
+       if ((err = snd_ctl_cwrite(card_ctl, &word_clock_sync)) < 0)
+               g_print("Unable to write word clock sync selection: %s\n", snd_strerror(err));
+}
+
+void master_clock_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *what = (char *) data;
+
+       if (!is_active(togglebutton))
+               return;
+       if (!strcmp(what, "Xtal")) {
+               master_clock_spdif_master(0);
+       } else if (!strcmp(what, "SPDIF")) {
+               master_clock_spdif_master(1);
+               master_clock_word_select(0);
+       } else if (!strcmp(what, "WordClock")) {
+               master_clock_spdif_master(1);
+               master_clock_word_select(1);
+       } else {
+               g_print("master_clock_toggled: %s ???\n", what);
+       }
+}
+
+gint master_clock_status_timeout_callback(gpointer data)
+{
+       snd_control_t sw;
+       int err;
+       
+       if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010)
+               return FALSE;
+       memset(&sw, 0, sizeof(sw));
+       sw.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(sw.id.name, "Word Clock Status");
+       if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
+               g_print("Unable to determine word clock status: %s\n", snd_strerror(err));
+       gtk_label_set_text(GTK_LABEL(hw_master_clock_status_label),
+                          sw.value.integer.value[0] ? "Locked" : "No signal");
+       return TRUE;
+}
+
+void volume_change_rate_update(void)
+{
+       int err;
+       
+       if ((err = snd_ctl_cread(card_ctl, &volume_rate)) < 0)
+               g_print("Unable to read volume change rate: %s\n", snd_strerror(err));
+       gtk_adjustment_set_value(GTK_ADJUSTMENT(hw_volume_change_adj), volume_rate.value.integer.value[0]);
+}
+
+void volume_change_rate_adj(GtkAdjustment *adj, gpointer data)
+{
+       int err;
+       
+       volume_rate.value.integer.value[0] = adj->value;
+       if ((err = snd_ctl_cwrite(card_ctl, &volume_rate)) < 0)
+               g_print("Unable to write volume change rate: %s\n", snd_strerror(err));
+}
+
+void spdif_output_update(void)
+{
+       int err, val;
+       
+       if (card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA44)
+               return;
+       if ((err = snd_ctl_cread(card_ctl, &spdif_output)) < 0)
+               g_print("Unable to read Delta S/PDIF output state: %s\n", snd_strerror(err));
+       val = spdif_output.value.integer.value[0];
+       if (val & 1) {          /* consumer */
+               toggle_set(hw_spdif_consumer_radio, TRUE);
+               if (val & 8) {
+                       toggle_set(hw_consumer_copyright_on_radio, TRUE);
+               } else {
+                       toggle_set(hw_consumer_copyright_off_radio, TRUE);
+               }
+               if (val & 0x10) {
+                       toggle_set(hw_consumer_emphasis_none_radio, TRUE);
+               } else {
+                       toggle_set(hw_consumer_emphasis_5015_radio, TRUE);
+               }
+               switch (val & 0x60) {
+               case 0x00: toggle_set(hw_consumer_category_dat_radio, TRUE); break;
+               case 0x20: toggle_set(hw_consumer_category_pcm_radio, TRUE); break;
+               case 0x40: toggle_set(hw_consumer_category_cd_radio, TRUE); break;
+               case 0x60: toggle_set(hw_consumer_category_general_radio, TRUE); break;
+               }
+               if (val & 0x80) {
+                       toggle_set(hw_consumer_copy_1st_radio, TRUE);
+               } else {
+                       toggle_set(hw_consumer_copy_original_radio, TRUE);
+               }
+       } else {
+               toggle_set(hw_spdif_professional_radio, TRUE);
+               if (val & 2) {
+                       toggle_set(hw_spdif_profi_audio_radio, TRUE);
+               } else {
+                       toggle_set(hw_spdif_profi_nonaudio_radio, TRUE);
+               }
+               switch (val & 0x60) {
+               case 0x00: toggle_set(hw_profi_emphasis_ccitt_radio, TRUE); break;
+               case 0x20: toggle_set(hw_profi_emphasis_none_radio, TRUE); break;
+               case 0x40: toggle_set(hw_profi_emphasis_5015_radio, TRUE); break;
+               case 0x60: toggle_set(hw_profi_emphasis_notid_radio, TRUE); break;
+               }
+               if (val & 0x80) {
+                       toggle_set(hw_profi_stream_notid_radio, TRUE);
+               } else {
+                       toggle_set(hw_profi_stream_stereo_radio, TRUE);
+               }
+       }
+}
+
+static void spdif_output_write(void)
+{
+       int err;
+
+       if ((err = snd_ctl_cwrite(card_ctl, &spdif_output)) < 0)
+               g_print("Unable to write Delta S/PDIF Output Defaults: %s\n", snd_strerror(err));
+}
+
+void profi_data_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (val & 1)
+               return;
+       if (!strcmp(str, "Audio")) {
+               val |= 0x02;
+       } else if (!strcmp(str, "Non-audio")) {
+               val &= ~0x02;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void profi_stream_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (val & 1)
+               return;
+       if (!strcmp(str, "NOTID")) {
+               val |= 0x80;
+       } else if (!strcmp(str, "Stereo")) {
+               val &= ~0x80;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void profi_emphasis_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (val & 1)
+               return;
+       if (!strcmp(str, "CCITT")) {
+               val &= ~0x60;
+       } else if (!strcmp(str, "No")) {
+               val &= ~0x60;
+               val |= 0x20;
+       } else if (!strcmp(str, "5015")) {
+               val &= ~0x60;
+               val |= 0x40;
+       } else if (!strcmp(str, "NOTID")) {
+               val |= 0x60;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void consumer_copyright_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (!(val & 1))
+               return;
+       if (!strcmp(str, "Copyright")) {
+               val |= 0x08;
+       } else if (!strcmp(str, "Permitted")) {
+               val &= ~0x08;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void consumer_copy_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (!(val & 1))
+               return;
+       if (!strcmp(str, "1st")) {
+               val |= 0x80;
+       } else if (!strcmp(str, "Original")) {
+               val &= ~0x80;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void consumer_emphasis_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (!(val & 1))
+               return;
+       if (!strcmp(str, "No")) {
+               val |= 0x10;
+       } else if (!strcmp(str, "5015")) {
+               val &= ~0x10;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void consumer_category_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int val = spdif_output.value.integer.value[0];
+       
+       if (!is_active(togglebutton))
+               return;
+       if (!(val & 1))
+               return;
+       if (!strcmp(str, "DAT")) {
+               val &= ~0x60;
+       } else if (!strcmp(str, "PCM")) {
+               val &= ~0x60;
+               val |= 0x20;
+       } else if (!strcmp(str, "CD")) {
+               val &= ~0x60;
+               val |= 0x40;
+       } else if (!strcmp(str, "General")) {
+               val |= 0x60;
+       }
+       spdif_output.value.integer.value[0] = val;
+       spdif_output_write();
+}
+
+void spdif_output_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       char *str = (char *)data;
+       int page;
+
+       if (is_active(togglebutton)) {
+               if (!strcmp(str, "Professional")) {
+                       if (spdif_output.value.integer.value[0] & 0x01) {
+                               /* default setup: audio, no emphasis */
+                               spdif_output.value.integer.value[0] = 0x22;
+                       }
+                       page = 0;
+               } else {
+                       if (!(spdif_output.value.integer.value[0] & 0x01)) {
+                               /* default setup: no emphasis, PCM encoder */
+                               spdif_output.value.integer.value[0] = 0x31;
+                       }
+                       page = 1;
+               }
+               spdif_output_write();
+               gtk_notebook_set_page(GTK_NOTEBOOK(hw_spdif_output_notebook), page);
+               spdif_output_update();
+       }
+}
+
+void spdif_input_update(void)
+{
+       int err;
+       
+       if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTADIO2496)
+               return;
+       if ((err = snd_ctl_cread(card_ctl, &spdif_input)) < 0)
+               g_print("Unable to read S/PDIF input switch: %s\n", snd_strerror(err));
+       if (spdif_input.value.integer.value[0]) {
+               toggle_set(hw_spdif_input_optical_radio, TRUE);
+       } else {
+               toggle_set(hw_spdif_input_coaxial_radio, TRUE);
+       }
+}
+
+void spdif_input_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       int err;
+       char *str = (char *)data;
+       
+       if (!is_active(togglebutton))
+               return;
+       if (!strcmp(str, "Optical"))
+               spdif_input.value.integer.value[0] = 1;
+       else
+               spdif_input.value.integer.value[0] = 0;
+       if ((err = snd_ctl_cwrite(card_ctl, &spdif_input)) < 0)
+               g_print("Unable to write S/PDIF input switch: %s\n", snd_strerror(err));
+}
+
+void hardware_init(void)
+{
+       memset(&spdif_master, 0, sizeof(spdif_master));
+       spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(spdif_master.id.name, "Multi Track S/PDIF Master");
+
+       memset(&word_clock_sync, 0, sizeof(spdif_master));
+       word_clock_sync.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(word_clock_sync.id.name, "Word Clock Sync");
+
+       memset(&volume_rate, 0, sizeof(volume_rate));
+       spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(volume_rate.id.name, "Multi Track Volume Rate");
+
+       memset(&spdif_input, 0, sizeof(spdif_input));
+       spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(spdif_input.id.name, "S/PDIF Input Optical");
+
+       memset(&spdif_output, 0, sizeof(spdif_output));
+       spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
+       strcpy(spdif_output.id.name, "Delta S/PDIF Output Defaults");
+}
+
+void hardware_postinit(void)
+{
+       master_clock_update();
+       volume_change_rate_update();
+       spdif_input_update();
+       spdif_output_update();
+}
diff --git a/envy24control/levelmeters.c b/envy24control/levelmeters.c
new file mode 100644 (file)
index 0000000..3e4caac
--- /dev/null
@@ -0,0 +1,229 @@
+/*****************************************************************************
+   levelmeters.c - Stereo level meters
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+static GdkGC *penGreenShadow[21] = { NULL, };
+static GdkGC *penGreenLight[21] = { NULL, };
+static GdkGC *penOrangeShadow[21] = { NULL, };
+static GdkGC *penOrangeLight[21] = { NULL, };
+static GdkGC *penRedShadow[21] = { NULL, };
+static GdkGC *penRedLight[21] = { NULL, };
+static GdkPixmap *pixmap[21] = { NULL, };
+static snd_control_t peaks;
+
+static void update_peak_switch(void)
+{
+       int err;
+
+       memset(&peaks, 0, sizeof(peaks));
+       peaks.id.iface = SND_CONTROL_IFACE_MIXER;
+       strcpy(peaks.id.name, "Multi Track Peak");
+       if ((err = snd_ctl_cread(card_ctl, &peaks)) < 0)
+               g_print("Unable to read peaks: %s\n", snd_strerror(err));
+}
+
+static void get_levels(int idx, int *l1, int *l2)
+{
+       *l1 = *l2 = 0;
+       
+       if (idx == 0) {
+               *l1 = peaks.value.integer.value[4 + 20];
+               *l2 = peaks.value.integer.value[4 + 21];
+       } else {
+               *l1 = *l2 = peaks.value.integer.value[4 + idx - 1];
+       }
+}
+
+static GdkGC *get_pen(int idx, int nRed, int nGreen, int nBlue)
+{
+       GdkColor *c;
+       GdkGC *gc;
+       
+       c = (GdkColor *)g_malloc(sizeof(GdkColor));
+       c->red = nRed;
+       c->green = nGreen;
+       c->blue = nBlue;
+       gdk_color_alloc(gdk_colormap_get_system(), c);
+       gc = gdk_gc_new(pixmap[idx]);
+       gdk_gc_set_foreground(gc, c);
+       return gc;
+}
+
+static int get_index(gchar *name)
+{
+       int result;
+
+       if (!strcmp(name, "DigitalMixer"))
+               return 0;
+       result = atoi(name + 5);
+       if (result < 1 || result > 20) {
+               g_print("Wrong drawing area ID: %s\n", name);
+               gtk_main_quit();
+       }
+       return result;
+}
+
+static void redraw_meters(int idx, int width, int height, int level1, int level2)
+{
+       int stereo = idx == 0;
+       int segment_width = stereo ? (width / 2) - 8 : width - 12;
+       int segments = (height - 6) / 4;
+       int green_segments = (segments / 4) * 3;
+       int red_segments = 2;
+       int orange_segments = segments - green_segments - red_segments;
+       int seg;
+       int segs_on1 = ((segments * level1) + 128) / 255;
+       int segs_on2 = ((segments * level2) + 128) / 255;
+
+       // g_print("segs_on1 = %i (%i), segs_on2 = %i (%i)\n", segs_on1, level1, segs_on2, level2);
+       for (seg = 0; seg < green_segments; seg++) {
+               gdk_draw_rectangle(pixmap[idx],
+                                  segs_on1 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
+                                  TRUE,
+                                  6, 3 + ((segments - seg - 1) * 4),
+                                  segment_width,
+                                  3);
+               if (stereo)
+                       gdk_draw_rectangle(pixmap[idx],
+                                          segs_on2 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
+                                          TRUE,
+                                          2 + (width / 2),
+                                          3 + ((segments - seg - 1) * 4),
+                                          segment_width,
+                                          3);
+               segs_on1--;
+               segs_on2--;
+       }
+       for (seg = green_segments; seg < green_segments + orange_segments; seg++) {
+               gdk_draw_rectangle(pixmap[idx],
+                                  segs_on1 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
+                                  TRUE,
+                                  6, 3 + ((segments - seg - 1) * 4),
+                                  segment_width,
+                                  3);
+               if (stereo)
+                       gdk_draw_rectangle(pixmap[idx],
+                                          segs_on2 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
+                                          TRUE,
+                                          2 + (width / 2),
+                                          3 + ((segments - seg - 1) * 4),
+                                          segment_width,
+                                          3);
+               segs_on1--;
+               segs_on2--;
+       }
+       for (seg = green_segments + orange_segments; seg < segments; seg++) {
+               gdk_draw_rectangle(pixmap[idx],
+                                  segs_on1 > 0 ? penRedLight[idx] : penRedShadow[idx],
+                                  TRUE,
+                                  6, 3 + ((segments - seg - 1) * 4),
+                                  segment_width,
+                                  3);
+               if (stereo)
+                       gdk_draw_rectangle(pixmap[idx],
+                                          segs_on2 > 0 ? penRedLight[idx] : penRedShadow[idx],
+                                          TRUE,
+                                          2 + (width / 2),
+                                          3 + ((segments - seg - 1) * 4),
+                                          segment_width,
+                                          3);
+               segs_on1--;
+               segs_on2--;
+       }
+}
+
+gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event)
+{
+       int idx = get_index(gtk_widget_get_name(widget));
+
+       if (pixmap[idx] != NULL)
+               gdk_pixmap_unref(pixmap[idx]);
+       pixmap[idx] = gdk_pixmap_new(widget->window,
+                                    widget->allocation.width,
+                                    widget->allocation.height,
+                                    -1);
+       penGreenShadow[idx] = get_pen(idx, 0, 0x77ff, 0);
+       penGreenLight[idx] = get_pen(idx, 0, 0xffff, 0);
+       penOrangeShadow[idx] = get_pen(idx, 0xddff, 0x55ff, 0);
+       penOrangeLight[idx] = get_pen(idx, 0xffff, 0x99ff, 0);
+       penRedShadow[idx] = get_pen(idx, 0xaaff, 0, 0);
+       penRedLight[idx] = get_pen(idx, 0xffff, 0, 0);
+       gdk_draw_rectangle(pixmap[idx],
+                          widget->style->black_gc,
+                          TRUE,
+                          0, 0,
+                          widget->allocation.width,
+                          widget->allocation.height);
+       // g_print("configure: %i:%i\n", widget->allocation.width, widget->allocation.height);
+       redraw_meters(idx, widget->allocation.width, widget->allocation.height, 0, 0);
+       return TRUE;
+}
+
+gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event)
+{
+       int idx = get_index(gtk_widget_get_name(widget));
+       int l1, l2;
+       
+       get_levels(idx, &l1, &l2);
+       redraw_meters(idx, widget->allocation.width, widget->allocation.height, l1, l2);
+       gdk_draw_pixmap(widget->window,
+                       widget->style->black_gc,
+                       pixmap[idx],
+                       event->area.x, event->area.y,
+                       event->area.x, event->area.y,
+                       event->area.width, event->area.height);
+       return FALSE;
+}
+
+gint level_meters_timeout_callback(gpointer data)
+{
+       GtkWidget *widget;
+       int idx, l1, l2;
+
+       update_peak_switch();
+       for (idx = 0; idx <= 20; idx++) {
+               get_levels(idx, &l1, &l2);
+               widget = idx == 0 ? mixer_mix_drawing : mixer_drawing[idx-1];
+               if (!GTK_WIDGET_VISIBLE(widget))
+                       continue;
+               redraw_meters(idx, widget->allocation.width, widget->allocation.height, l1, l2);
+               gdk_draw_pixmap(widget->window,
+                               widget->style->black_gc,
+                               pixmap[idx],
+                               0, 0,
+                               0, 0,
+                               widget->allocation.width, widget->allocation.height);   
+       }
+       return TRUE;
+}
+
+void level_meters_reset_peaks(GtkButton *button, gpointer data)
+{
+}
+
+void level_meters_init(void)
+{
+       memset(&peaks, 0, sizeof(peaks));
+}
+
+void level_meters_postinit(void)
+{
+       level_meters_timeout_callback(NULL);
+}
diff --git a/envy24control/mixer.c b/envy24control/mixer.c
new file mode 100644 (file)
index 0000000..27e2762
--- /dev/null
@@ -0,0 +1,188 @@
+/*****************************************************************************
+   mixer.c - mixer code
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+#define toggle_set(widget, state) \
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
+
+static int is_active(GtkWidget *widget)
+{
+       return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
+}
+
+void mixer_update_stream(int stream, int vol_flag, int sw_flag)
+{
+       snd_control_t vol, sw;
+       int err;
+       
+       if (vol_flag) {
+               memset(&vol, 0, sizeof(vol));
+               vol.id.iface = SND_CONTROL_IFACE_MIXER;
+               strcpy(vol.id.name, stream <= 10 ? "Multi Playback Volume" : "Multi Capture Volume");
+               vol.id.index = (stream - 1) % 10;
+               if ((err = snd_ctl_cread(card_ctl, &vol)) < 0)
+                       g_print("Unable to read multi playback volume: %s\n", snd_strerror(err));
+               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), 96 - vol.value.integer.value[0]);
+               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), 96 - vol.value.integer.value[1]);
+               if (vol.value.integer.value[0] != vol.value.integer.value[1])
+                       toggle_set(mixer_stereo_toggle[stream-1], FALSE);
+       }
+       if (sw_flag) {
+               memset(&sw, 0, sizeof(sw));
+               sw.id.iface = SND_CONTROL_IFACE_MIXER;
+               strcpy(sw.id.name, stream <= 10 ? "Multi Playback Switch" : "Multi Capture Switch");
+               sw.id.index = (stream - 1) % 10;
+               if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
+                       g_print("Unable to read multi playback switch: %s\n", snd_strerror(err));
+               toggle_set(mixer_solo_toggle[stream-1][0], sw.value.integer.value[0] ? TRUE : FALSE);
+               toggle_set(mixer_solo_toggle[stream-1][1], sw.value.integer.value[1] ? TRUE : FALSE);
+               toggle_set(mixer_mute_toggle[stream-1][0], !sw.value.integer.value[0] ? TRUE : FALSE);
+               toggle_set(mixer_mute_toggle[stream-1][1], !sw.value.integer.value[1] ? TRUE : FALSE);
+               if (sw.value.integer.value[0] != sw.value.integer.value[1])
+                       toggle_set(mixer_stereo_toggle[stream-1], FALSE);
+       }
+}
+
+static void set_switch1(int stream, int left, int right)
+{
+       snd_control_t sw;
+       int err;
+       
+       memset(&sw, 0, sizeof(sw));
+       sw.id.iface = SND_CONTROL_IFACE_MIXER;
+       strcpy(sw.id.name, stream <= 10 ? "Multi Playback Switch" : "Multi Capture Switch");
+       sw.id.index = (stream - 1) % 10;
+       if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
+               g_print("Unable to read multi switch: %s\n", snd_strerror(err));
+       if (left >= 0)
+               sw.value.integer.value[0] = left != 0;
+       if (right >= 0)
+               sw.value.integer.value[1] = right != 0;
+       if ((err = snd_ctl_cwrite(card_ctl, &sw)) < 0 && err != -EBUSY)
+               g_print("Unable to write multi switch: %s\n", snd_strerror(err));
+}
+
+void mixer_toggled_solo(GtkWidget *togglebutton, gpointer data)
+{
+       int stream = (long)data >> 16;
+       int button = (long)data & 1;
+       int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
+       int vol[2] = { -1, -1 };
+
+       if (is_active(togglebutton)) {
+               if (is_active(mixer_mute_toggle[stream-1][button]))
+                       toggle_set(mixer_mute_toggle[stream-1][button], FALSE);
+               vol[button] = 1;
+               if (stereo) {
+                       if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
+                       if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
+                       vol[button ^ 1] = 1;
+               }
+       } else {
+               if (!is_active(mixer_mute_toggle[stream-1][button]))
+                       toggle_set(mixer_mute_toggle[stream-1][button], TRUE);
+               vol[button] = 0;
+               if (stereo) {
+                       if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
+                       if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
+                       vol[button ^ 1] = 0;
+               }
+       }
+       set_switch1(stream, vol[0], vol[1]);
+}
+
+void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data)
+{
+       int stream = (long)data >> 16;
+       int button = (long)data & 1;
+       int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
+       int vol[2] = { -1, -1 };
+
+       if (is_active(togglebutton)) {
+               if (is_active(mixer_solo_toggle[stream-1][button]))
+                       toggle_set(mixer_solo_toggle[stream-1][button], FALSE);
+               vol[button] = 0;
+               if (stereo) {
+                       if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
+                       if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
+                       vol[button ^ 1] = 0;
+               }
+       } else {
+               if (!is_active(mixer_solo_toggle[stream-1][button]))
+                       toggle_set(mixer_solo_toggle[stream-1][button], TRUE);
+               vol[button] = 1;
+               if (stereo) {
+                       if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
+                       if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
+                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
+                       vol[button ^ 1] = 1;
+               }
+       }
+       set_switch1(stream, vol[0], vol[1]);
+}
+
+static void set_volume1(int stream, int left, int right)
+{
+       snd_control_t vol;
+       int err;
+       
+       memset(&vol, 0, sizeof(vol));
+       vol.id.iface = SND_CONTROL_IFACE_MIXER;
+       strcpy(vol.id.name, stream <= 10 ? "Multi Playback Volume" : "Multi Capture Volume");
+       vol.id.index = (stream - 1) % 10;
+       if ((err = snd_ctl_cread(card_ctl, &vol)) < 0)
+               g_print("Unable to read multi volume: %s\n", snd_strerror(err));
+       if (left >= 0)
+               vol.value.integer.value[0] = left;
+       if (right >= 0)
+               vol.value.integer.value[1] = right;
+       if ((err = snd_ctl_cwrite(card_ctl, &vol)) < 0 && err != -EBUSY)
+               g_print("Unable to write multi volume: %s\n", snd_strerror(err));
+}
+
+void mixer_adjust(GtkAdjustment *adj, gpointer data)
+{
+       int stream = (long)data >> 16;
+       int button = (long)data & 1;
+       int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
+       int vol[2] = { -1, -1 };
+       
+       vol[button] = 96 - adj->value;
+       if (stereo) {
+               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][button ^ 1]), adj->value);
+               vol[button ^ 1] = 96 - adj->value;
+       }
+       set_volume1(stream, vol[0], vol[1]);
+}
+
+void mixer_postinit(void)
+{
+       int stream;
+
+       for (stream = 1; stream <= 20; stream++)
+               mixer_update_stream(stream, 1, 1);
+}
diff --git a/envy24control/patchbay.c b/envy24control/patchbay.c
new file mode 100644 (file)
index 0000000..8b3227c
--- /dev/null
@@ -0,0 +1,195 @@
+/*****************************************************************************
+   patchbay.c - patchbay/router code
+   Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
+   
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+******************************************************************************/
+
+#include "envy24control.h"
+
+static snd_control_t routes;
+
+#define toggle_set(widget, state) \
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
+
+static int is_active(GtkWidget *widget)
+{
+       return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
+}
+
+static int get_toggle_index(int stream)
+{
+       unsigned short psdout = routes.value.bytes.data[0] |
+                               (routes.value.bytes.data[1] << 8);
+       unsigned short spdout = routes.value.bytes.data[2] |
+                               (routes.value.bytes.data[3] << 8);
+       unsigned int capture = routes.value.bytes.data[4] |
+                              (routes.value.bytes.data[5] << 8) |
+                              (routes.value.bytes.data[6] << 16) |
+                              (routes.value.bytes.data[7] << 24);
+       int right = (stream - 1) & 1;
+       int source = (stream - 1) >> 1;
+
+       stream--;
+       if (stream < 0 || stream > 9) {
+               g_print("get_toggle_index (1)\n");
+               return 0;
+       }
+       if (stream < 8) {       /* SPDOUT */
+               int psdout_shift = (source << 1) + (right ? 8 : 0);
+               int capture_shift = (source << 3) + (right ? 4 : 0);
+               int setup = (psdout >> psdout_shift) & 3;
+               int csetup = (capture >> capture_shift) & 15;
+               
+               switch (setup) {
+               case 0:                                 /* PCM Out */
+                       return 0;
+               case 1:                                 /* digital mixer */
+                       if (stream == 0 || stream == 1)
+                               return 1;
+                       return 0;
+               case 2:
+                       return (csetup & 7) + 4;
+               case 3:
+                       if (csetup & 8)
+                               return 3;               /* S/PDIF right */
+                       return 2;                       /* S/PDIF left */
+               }
+       } else {        /* SPDOUT */
+               int spdout_shift = right ? 2 : 0;
+               int spdout_shift1 = right ? 12 : 8;
+               int setup = (spdout >> spdout_shift) & 3;
+               int setup1 = (spdout >> spdout_shift1) & 15;
+               
+               switch (setup) {
+               case 0:                                 /* PCM Out */
+                       return 0;
+               case 1:                                 /* digital mixer */
+                       if (stream == 0 || stream == 1)
+                               return 1;
+                       return 0;
+               case 2:
+                       return (setup1 & 7) + 4;
+               case 3:
+                       if (setup1 & 8)
+                               return 3;               /* S/PDIF right */
+                       return 2;                       /* S/PDIF left */
+               }
+       }
+       return 0;
+}
+
+void patchbay_update(void)
+{
+       int stream, tidx, err;
+
+       if ((err = snd_ctl_cread(card_ctl, &routes)) < 0) {
+               g_print("Multi track routes read error: %s\n", snd_strerror(err));
+               return;
+       }
+       for (stream = 1; stream <= 10; stream++) {
+               tidx = get_toggle_index(stream);
+               toggle_set(router_radio[stream - 1][tidx], TRUE);
+       }
+}
+
+static void set_routes(int stream, int idx)
+{
+       unsigned short psdout = routes.value.bytes.data[0] |
+                               (routes.value.bytes.data[1] << 8);
+       unsigned short spdout = routes.value.bytes.data[2] |
+                               (routes.value.bytes.data[3] << 8);
+       unsigned int capture = routes.value.bytes.data[4] |
+                              (routes.value.bytes.data[5] << 8) |
+                              (routes.value.bytes.data[6] << 16) |
+                              (routes.value.bytes.data[7] << 24);
+       int right = (stream - 1) & 1;
+       int source = (stream - 1) >> 1;
+       int err;
+
+       stream--;
+       if (stream < 0 || stream > 9) {
+               g_print("set_routes (1)\n");
+               return;
+       }
+       if (stream < 8) {       /* SPDOUT */
+               int psdout_shift = (source << 1) + (right ? 8 : 0);
+               int capture_shift = (source << 3) + (right ? 4 : 0);
+               psdout &= ~(3 << psdout_shift);
+               if (idx == 0) {                         /* PCM Out */
+                       /* nothing */ ;
+               } else if (idx == 1) {                  /* digital mixer */
+                       if (stream == 0 || stream == 1)
+                               psdout |= 1 << psdout_shift;
+               } else if (idx == 2 || idx == 3) {      /* S/PDIF left & right */
+                       psdout |= 3 << psdout_shift;
+                       capture &= ~(1 << (capture_shift + 3));
+                       capture |= (idx - 2) << (capture_shift + 3);
+               } else {
+                       psdout |= 2 << psdout_shift;
+                       capture &= ~(7 << capture_shift);
+                       capture |= ((idx - 4) & 7) << capture_shift;
+               }
+       } else {        /* SPDOUT */
+               int spdout_shift = right ? 2 : 0;
+               int spdout_shift1 = right ? 12 : 8;
+               spdout &= ~(3 << spdout_shift);
+               if (idx == 0) {                         /* PCM Out 9 & 10 */
+                       /* nothing */ ;
+               } else if (idx == 1) {                  /* digital mixer */
+                       spdout |= 1 << spdout_shift;
+               } else if (idx == 2 || idx == 3) {      /* S/PDIF left & right */
+                       spdout |= 3 << spdout_shift;
+                       spdout &= ~(1 << (spdout_shift1 + 3));
+                       spdout |= (idx - 2) << (spdout_shift1 + 3);
+               } else {
+                       spdout |= 2 << spdout_shift;
+                       spdout &= ~(7 << spdout_shift1);
+                       spdout |= ((idx - 4) & 7) << spdout_shift1;
+               }
+       }
+       routes.value.bytes.data[0] = psdout & 0xff;
+       routes.value.bytes.data[1] = (psdout >> 8) & 0xff;
+       routes.value.bytes.data[2] = spdout & 0xff;
+       routes.value.bytes.data[3] = (spdout >> 8) & 0xff;
+       routes.value.bytes.data[4] = capture & 0xff;
+       routes.value.bytes.data[5] = (capture >> 8) & 0xff;
+       routes.value.bytes.data[6] = (capture >> 16) & 0xff;
+       routes.value.bytes.data[7] = (capture >> 24) & 0xff;
+       // g_print("psdout = 0x%x, spdout = 0x%x, capture = 0x%x\n", psdout, spdout, capture);
+       if ((err = snd_ctl_cwrite(card_ctl, &routes)) < 0)
+               g_print("Multi track route write error: %s\n", snd_strerror(err));
+}
+
+void patchbay_toggled(GtkWidget *togglebutton, gpointer data)
+{
+       int stream = (long)data >> 16;
+       int what = (long)data & 0xffff;
+
+       if (is_active(togglebutton))
+               set_routes(stream, what);
+}
+
+void patchbay_init(void)
+{
+       memset(&routes, 0, sizeof(routes));
+       routes.id.iface = SND_CONTROL_IFACE_MIXER;
+       strcpy(routes.id.name, "Multi Track Route");
+}
+
+void patchbay_postinit(void)
+{
+       patchbay_update();
+}