From 8785f9288ec4a5a1fe407c6d6134e058309a837f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 29 Oct 2000 21:51:51 +0000 Subject: [PATCH 1/1] Initial version --- envy24control/AUTHORS | 1 + envy24control/COPYING | 282 ++++++++ envy24control/Makefile.am | 9 + envy24control/configure.in | 11 + envy24control/cvscompile | 22 + envy24control/driverevents.c | 83 +++ envy24control/envy24control.c | 1132 +++++++++++++++++++++++++++++++++ envy24control/envy24control.h | 127 ++++ envy24control/hardware.c | 415 ++++++++++++ envy24control/levelmeters.c | 229 +++++++ envy24control/mixer.c | 188 ++++++ envy24control/patchbay.c | 195 ++++++ 12 files changed, 2694 insertions(+) create mode 100644 envy24control/AUTHORS create mode 100644 envy24control/COPYING create mode 100644 envy24control/Makefile.am create mode 100644 envy24control/configure.in create mode 100644 envy24control/cvscompile create mode 100644 envy24control/driverevents.c create mode 100644 envy24control/envy24control.c create mode 100644 envy24control/envy24control.h create mode 100644 envy24control/hardware.c create mode 100644 envy24control/levelmeters.c create mode 100644 envy24control/mixer.c create mode 100644 envy24control/patchbay.c diff --git a/envy24control/AUTHORS b/envy24control/AUTHORS new file mode 100644 index 0000000..8b658f1 --- /dev/null +++ b/envy24control/AUTHORS @@ -0,0 +1 @@ +Jaroslav Kysela diff --git a/envy24control/COPYING b/envy24control/COPYING new file mode 100644 index 0000000..9392a19 --- /dev/null +++ b/envy24control/COPYING @@ -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 index 0000000..8708de1 --- /dev/null +++ b/envy24control/Makefile.am @@ -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 index 0000000..d274cb5 --- /dev/null +++ b/envy24control/configure.in @@ -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 index 0000000..e54e9cd --- /dev/null +++ b/envy24control/cvscompile @@ -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 index 0000000..88596e7 --- /dev/null +++ b/envy24control/driverevents.c @@ -0,0 +1,83 @@ +/***************************************************************************** + driverevents.c - Events from the driver processing + Copyright (C) 2000 by Jaroslav Kysela + + 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 index 0000000..a92f3d0 --- /dev/null +++ b/envy24control/envy24control.c @@ -0,0 +1,1132 @@ +/***************************************************************************** + envy24control.c - Env24 chipset (ICE1712) control utility + Copyright (C) 2000 by Jaroslav Kysela + + 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 "); + 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 index 0000000..03c8b49 --- /dev/null +++ b/envy24control/envy24control.h @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..3884f74 --- /dev/null +++ b/envy24control/hardware.c @@ -0,0 +1,415 @@ +/***************************************************************************** + hardware.c - Hardware Settings + Copyright (C) 2000 by Jaroslav Kysela + + 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 index 0000000..3e4caac --- /dev/null +++ b/envy24control/levelmeters.c @@ -0,0 +1,229 @@ +/***************************************************************************** + levelmeters.c - Stereo level meters + Copyright (C) 2000 by Jaroslav Kysela + + 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 index 0000000..27e2762 --- /dev/null +++ b/envy24control/mixer.c @@ -0,0 +1,188 @@ +/***************************************************************************** + mixer.c - mixer code + Copyright (C) 2000 by Jaroslav Kysela + + 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 index 0000000..8b3227c --- /dev/null +++ b/envy24control/patchbay.c @@ -0,0 +1,195 @@ +/***************************************************************************** + patchbay.c - patchbay/router code + Copyright (C) 2000 by Jaroslav Kysela + + 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(); +} -- 2.47.1