Initial version

This commit is contained in:
Jaroslav Kysela 2000-10-29 21:51:51 +00:00
commit 8785f9288e
12 changed files with 2694 additions and 0 deletions

1
envy24control/AUTHORS Normal file
View file

@ -0,0 +1 @@
Jaroslav Kysela <perex@suse.cz>

282
envy24control/COPYING Normal file
View file

@ -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

View file

@ -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 *~

View file

@ -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)

22
envy24control/cvscompile Normal file
View file

@ -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

View file

@ -0,0 +1,83 @@
/*****************************************************************************
driverevents.c - Events from the driver processing
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include "envy24control.h"
static void control_value(snd_ctl_t *handle, void *private_data, snd_control_id_t *id)
{
if (id->iface == SND_CONTROL_IFACE_PCM) {
if (!strcmp(id->name, "Multi Track Route")) {
patchbay_update();
return;
}
if (!strcmp(id->name, "Multi Track S/PDIF Master")) {
master_clock_update();
return;
}
if (!strcmp(id->name, "Word Clock Sync")) {
master_clock_update();
return;
}
if (!strcmp(id->name, "Multi Track Volume Rate")) {
volume_change_rate_update();
return;
}
if (!strcmp(id->name, "S/PDIF Input Optical")) {
spdif_input_update();
return;
}
if (!strcmp(id->name, "Delta S/PDIF Output Defaults")) {
spdif_output_update();
return;
}
}
if (id->iface == SND_CONTROL_IFACE_MIXER) {
if (!strcmp(id->name, "Multi Playback Volume")) {
mixer_update_stream(id->index + 1, 1, 0);
return;
}
if (!strcmp(id->name, "Multi Capture Volume")) {
mixer_update_stream(id->index + 11, 1, 0);
return;
}
if (!strcmp(id->name, "Multi Playback Switch")) {
mixer_update_stream(id->index + 1, 0, 1);
return;
}
if (!strcmp(id->name, "Multi Capture Switch")) {
mixer_update_stream(id->index + 11, 0, 1);
return;
}
}
}
static snd_ctl_callbacks_t control_callbacks = {
private_data: NULL,
rebuild: NULL, /* FIXME!! */
value: control_value,
change: NULL,
add: NULL,
remove: NULL,
reserved: { NULL, }
};
void control_input_callback(gpointer data, gint source, GdkInputCondition condition)
{
snd_ctl_read(card_ctl, &control_callbacks);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,127 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <gtk/gtk.h>
#include <sys/asoundlib.h>
#define ICE1712_SUBDEVICE_DELTA1010 0x121430d6
#define ICE1712_SUBDEVICE_DELTADIO2496 0x121431d6
#define ICE1712_SUBDEVICE_DELTA66 0x121432d6
#define ICE1712_SUBDEVICE_DELTA44 0x121433d6
typedef struct {
unsigned int subvendor; /* PCI[2c-2f] */
unsigned char size; /* size of EEPROM image in bytes */
unsigned char version; /* must be 1 */
unsigned char codec; /* codec configuration PCI[60] */
unsigned char aclink; /* ACLink configuration PCI[61] */
unsigned char i2sID; /* PCI[62] */
unsigned char spdif; /* S/PDIF configuration PCI[63] */
unsigned char gpiomask; /* GPIO initial mask, 0 = write, 1 = don't */
unsigned char gpiostate; /* GPIO initial state */
unsigned char gpiodir; /* GPIO direction state */
unsigned short ac97main;
unsigned short ac97pcm;
unsigned short ac97rec;
unsigned char ac97recsrc;
unsigned char dacID[4]; /* I2S IDs for DACs */
unsigned char adcID[4]; /* I2S IDs for ADCs */
unsigned char extra[4];
} ice1712_eeprom_t;
extern snd_ctl_t *card_ctl;
extern ice1712_eeprom_t card_eeprom;
extern GtkWidget *mixer_mix_drawing;
extern GtkWidget *mixer_clear_peaks_button;
extern GtkWidget *mixer_drawing[20];
extern GtkObject *mixer_adj[20][2];
extern GtkWidget *mixer_vscale[20][2];
extern GtkWidget *mixer_solo_toggle[20][2];
extern GtkWidget *mixer_mute_toggle[20][2];
extern GtkWidget *mixer_stereo_toggle[20];
extern GtkWidget *router_radio[10][12];
extern GtkWidget *hw_master_clock_xtal_radio;
extern GtkWidget *hw_master_clock_spdif_radio;
extern GtkWidget *hw_master_clock_word_radio;
extern GtkWidget *hw_master_clock_status_label;
extern GtkObject *hw_volume_change_adj;
extern GtkWidget *hw_volume_change_spin;
extern GtkWidget *hw_spdif_profi_nonaudio_radio;
extern GtkWidget *hw_spdif_profi_audio_radio;
extern GtkWidget *hw_profi_stream_stereo_radio;
extern GtkWidget *hw_profi_stream_notid_radio;
extern GtkWidget *hw_profi_emphasis_none_radio;
extern GtkWidget *hw_profi_emphasis_5015_radio;
extern GtkWidget *hw_profi_emphasis_ccitt_radio;
extern GtkWidget *hw_profi_emphasis_notid_radio;
extern GtkWidget *hw_consumer_copyright_on_radio;
extern GtkWidget *hw_consumer_copyright_off_radio;
extern GtkWidget *hw_consumer_copy_1st_radio;
extern GtkWidget *hw_consumer_copy_original_radio;
extern GtkWidget *hw_consumer_emphasis_none_radio;
extern GtkWidget *hw_consumer_emphasis_5015_radio;
extern GtkWidget *hw_consumer_category_dat_radio;
extern GtkWidget *hw_consumer_category_pcm_radio;
extern GtkWidget *hw_consumer_category_cd_radio;
extern GtkWidget *hw_consumer_category_general_radio;
extern GtkWidget *hw_spdif_professional_radio;
extern GtkWidget *hw_spdif_consumer_radio;
extern GtkWidget *hw_spdif_output_notebook;
extern GtkWidget *hw_spdif_input_coaxial_radio;
extern GtkWidget *hw_spdif_input_optical_radio;
gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event);
gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event);
gint level_meters_timeout_callback(gpointer data);
void level_meters_reset_peaks(GtkButton *button, gpointer data);
void level_meters_init(void);
void level_meters_postinit(void);
void mixer_update_stream(int stream, int vol_flag, int sw_flag);
void mixer_toggled_solo(GtkWidget *togglebutton, gpointer data);
void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data);
void mixer_adjust(GtkAdjustment *adj, gpointer data);
void mixer_postinit(void);
void patchbay_update(void);
void patchbay_toggled(GtkWidget *togglebutton, gpointer data);
void patchbay_init(void);
void patchbay_postinit(void);
void master_clock_update(void);
void master_clock_toggled(GtkWidget *togglebutton, gpointer data);
gint master_clock_status_timeout_callback(gpointer data);
void volume_change_rate_update(void);
void volume_change_rate_adj(GtkAdjustment *adj, gpointer data);
void profi_data_toggled(GtkWidget *togglebutton, gpointer data);
void profi_stream_toggled(GtkWidget *togglebutton, gpointer data);
void profi_emphasis_toggled(GtkWidget *togglebutton, gpointer data);
void consumer_copyright_toggled(GtkWidget *togglebutton, gpointer data);
void consumer_copy_toggled(GtkWidget *togglebutton, gpointer data);
void consumer_emphasis_toggled(GtkWidget *togglebutton, gpointer data);
void consumer_category_toggled(GtkWidget *togglebutton, gpointer data);
void spdif_output_update(void);
void spdif_output_toggled(GtkWidget *togglebutton, gpointer data);
void spdif_input_update(void);
void spdif_input_toggled(GtkWidget *togglebutton, gpointer data);
void hardware_init(void);
void hardware_postinit(void);
void control_input_callback(gpointer data, gint source, GdkInputCondition condition);
void mixer_input_callback(gpointer data, gint source, GdkInputCondition condition);

415
envy24control/hardware.c Normal file
View file

@ -0,0 +1,415 @@
/*****************************************************************************
hardware.c - Hardware Settings
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include "envy24control.h"
static snd_control_t spdif_master;
static snd_control_t word_clock_sync;
static snd_control_t volume_rate;
static snd_control_t spdif_input;
static snd_control_t spdif_output;
#define toggle_set(widget, state) \
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
static int is_active(GtkWidget *widget)
{
return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
}
void master_clock_update(void)
{
int err;
if ((err = snd_ctl_cread(card_ctl, &spdif_master)) < 0)
g_print("Unable to read S/PDIF master state: %s\n", snd_strerror(err));
if (card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010) {
if ((err = snd_ctl_cread(card_ctl, &word_clock_sync)) < 0)
g_print("Unable to read word clock sync selection: %s\n", snd_strerror(err));
}
if (spdif_master.value.integer.value[0]) {
if (word_clock_sync.value.integer.value[0]) {
toggle_set(hw_master_clock_word_radio, TRUE);
} else {
toggle_set(hw_master_clock_spdif_radio, TRUE);
}
} else {
toggle_set(hw_master_clock_xtal_radio, TRUE);
}
master_clock_status_timeout_callback(NULL);
}
static void master_clock_spdif_master(int on)
{
int err;
spdif_master.value.integer.value[0] = on ? 1 : 0;
if ((err = snd_ctl_cwrite(card_ctl, &spdif_master)) < 0)
g_print("Unable to write S/PDIF master state: %s\n", snd_strerror(err));
}
static void master_clock_word_select(int on)
{
int err;
if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010)
return;
word_clock_sync.value.integer.value[0] = on ? 1 : 0;
if ((err = snd_ctl_cwrite(card_ctl, &word_clock_sync)) < 0)
g_print("Unable to write word clock sync selection: %s\n", snd_strerror(err));
}
void master_clock_toggled(GtkWidget *togglebutton, gpointer data)
{
char *what = (char *) data;
if (!is_active(togglebutton))
return;
if (!strcmp(what, "Xtal")) {
master_clock_spdif_master(0);
} else if (!strcmp(what, "SPDIF")) {
master_clock_spdif_master(1);
master_clock_word_select(0);
} else if (!strcmp(what, "WordClock")) {
master_clock_spdif_master(1);
master_clock_word_select(1);
} else {
g_print("master_clock_toggled: %s ???\n", what);
}
}
gint master_clock_status_timeout_callback(gpointer data)
{
snd_control_t sw;
int err;
if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010)
return FALSE;
memset(&sw, 0, sizeof(sw));
sw.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(sw.id.name, "Word Clock Status");
if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
g_print("Unable to determine word clock status: %s\n", snd_strerror(err));
gtk_label_set_text(GTK_LABEL(hw_master_clock_status_label),
sw.value.integer.value[0] ? "Locked" : "No signal");
return TRUE;
}
void volume_change_rate_update(void)
{
int err;
if ((err = snd_ctl_cread(card_ctl, &volume_rate)) < 0)
g_print("Unable to read volume change rate: %s\n", snd_strerror(err));
gtk_adjustment_set_value(GTK_ADJUSTMENT(hw_volume_change_adj), volume_rate.value.integer.value[0]);
}
void volume_change_rate_adj(GtkAdjustment *adj, gpointer data)
{
int err;
volume_rate.value.integer.value[0] = adj->value;
if ((err = snd_ctl_cwrite(card_ctl, &volume_rate)) < 0)
g_print("Unable to write volume change rate: %s\n", snd_strerror(err));
}
void spdif_output_update(void)
{
int err, val;
if (card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA44)
return;
if ((err = snd_ctl_cread(card_ctl, &spdif_output)) < 0)
g_print("Unable to read Delta S/PDIF output state: %s\n", snd_strerror(err));
val = spdif_output.value.integer.value[0];
if (val & 1) { /* consumer */
toggle_set(hw_spdif_consumer_radio, TRUE);
if (val & 8) {
toggle_set(hw_consumer_copyright_on_radio, TRUE);
} else {
toggle_set(hw_consumer_copyright_off_radio, TRUE);
}
if (val & 0x10) {
toggle_set(hw_consumer_emphasis_none_radio, TRUE);
} else {
toggle_set(hw_consumer_emphasis_5015_radio, TRUE);
}
switch (val & 0x60) {
case 0x00: toggle_set(hw_consumer_category_dat_radio, TRUE); break;
case 0x20: toggle_set(hw_consumer_category_pcm_radio, TRUE); break;
case 0x40: toggle_set(hw_consumer_category_cd_radio, TRUE); break;
case 0x60: toggle_set(hw_consumer_category_general_radio, TRUE); break;
}
if (val & 0x80) {
toggle_set(hw_consumer_copy_1st_radio, TRUE);
} else {
toggle_set(hw_consumer_copy_original_radio, TRUE);
}
} else {
toggle_set(hw_spdif_professional_radio, TRUE);
if (val & 2) {
toggle_set(hw_spdif_profi_audio_radio, TRUE);
} else {
toggle_set(hw_spdif_profi_nonaudio_radio, TRUE);
}
switch (val & 0x60) {
case 0x00: toggle_set(hw_profi_emphasis_ccitt_radio, TRUE); break;
case 0x20: toggle_set(hw_profi_emphasis_none_radio, TRUE); break;
case 0x40: toggle_set(hw_profi_emphasis_5015_radio, TRUE); break;
case 0x60: toggle_set(hw_profi_emphasis_notid_radio, TRUE); break;
}
if (val & 0x80) {
toggle_set(hw_profi_stream_notid_radio, TRUE);
} else {
toggle_set(hw_profi_stream_stereo_radio, TRUE);
}
}
}
static void spdif_output_write(void)
{
int err;
if ((err = snd_ctl_cwrite(card_ctl, &spdif_output)) < 0)
g_print("Unable to write Delta S/PDIF Output Defaults: %s\n", snd_strerror(err));
}
void profi_data_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (val & 1)
return;
if (!strcmp(str, "Audio")) {
val |= 0x02;
} else if (!strcmp(str, "Non-audio")) {
val &= ~0x02;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void profi_stream_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (val & 1)
return;
if (!strcmp(str, "NOTID")) {
val |= 0x80;
} else if (!strcmp(str, "Stereo")) {
val &= ~0x80;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void profi_emphasis_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (val & 1)
return;
if (!strcmp(str, "CCITT")) {
val &= ~0x60;
} else if (!strcmp(str, "No")) {
val &= ~0x60;
val |= 0x20;
} else if (!strcmp(str, "5015")) {
val &= ~0x60;
val |= 0x40;
} else if (!strcmp(str, "NOTID")) {
val |= 0x60;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void consumer_copyright_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (!(val & 1))
return;
if (!strcmp(str, "Copyright")) {
val |= 0x08;
} else if (!strcmp(str, "Permitted")) {
val &= ~0x08;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void consumer_copy_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (!(val & 1))
return;
if (!strcmp(str, "1st")) {
val |= 0x80;
} else if (!strcmp(str, "Original")) {
val &= ~0x80;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void consumer_emphasis_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (!(val & 1))
return;
if (!strcmp(str, "No")) {
val |= 0x10;
} else if (!strcmp(str, "5015")) {
val &= ~0x10;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void consumer_category_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int val = spdif_output.value.integer.value[0];
if (!is_active(togglebutton))
return;
if (!(val & 1))
return;
if (!strcmp(str, "DAT")) {
val &= ~0x60;
} else if (!strcmp(str, "PCM")) {
val &= ~0x60;
val |= 0x20;
} else if (!strcmp(str, "CD")) {
val &= ~0x60;
val |= 0x40;
} else if (!strcmp(str, "General")) {
val |= 0x60;
}
spdif_output.value.integer.value[0] = val;
spdif_output_write();
}
void spdif_output_toggled(GtkWidget *togglebutton, gpointer data)
{
char *str = (char *)data;
int page;
if (is_active(togglebutton)) {
if (!strcmp(str, "Professional")) {
if (spdif_output.value.integer.value[0] & 0x01) {
/* default setup: audio, no emphasis */
spdif_output.value.integer.value[0] = 0x22;
}
page = 0;
} else {
if (!(spdif_output.value.integer.value[0] & 0x01)) {
/* default setup: no emphasis, PCM encoder */
spdif_output.value.integer.value[0] = 0x31;
}
page = 1;
}
spdif_output_write();
gtk_notebook_set_page(GTK_NOTEBOOK(hw_spdif_output_notebook), page);
spdif_output_update();
}
}
void spdif_input_update(void)
{
int err;
if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTADIO2496)
return;
if ((err = snd_ctl_cread(card_ctl, &spdif_input)) < 0)
g_print("Unable to read S/PDIF input switch: %s\n", snd_strerror(err));
if (spdif_input.value.integer.value[0]) {
toggle_set(hw_spdif_input_optical_radio, TRUE);
} else {
toggle_set(hw_spdif_input_coaxial_radio, TRUE);
}
}
void spdif_input_toggled(GtkWidget *togglebutton, gpointer data)
{
int err;
char *str = (char *)data;
if (!is_active(togglebutton))
return;
if (!strcmp(str, "Optical"))
spdif_input.value.integer.value[0] = 1;
else
spdif_input.value.integer.value[0] = 0;
if ((err = snd_ctl_cwrite(card_ctl, &spdif_input)) < 0)
g_print("Unable to write S/PDIF input switch: %s\n", snd_strerror(err));
}
void hardware_init(void)
{
memset(&spdif_master, 0, sizeof(spdif_master));
spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(spdif_master.id.name, "Multi Track S/PDIF Master");
memset(&word_clock_sync, 0, sizeof(spdif_master));
word_clock_sync.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(word_clock_sync.id.name, "Word Clock Sync");
memset(&volume_rate, 0, sizeof(volume_rate));
spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(volume_rate.id.name, "Multi Track Volume Rate");
memset(&spdif_input, 0, sizeof(spdif_input));
spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(spdif_input.id.name, "S/PDIF Input Optical");
memset(&spdif_output, 0, sizeof(spdif_output));
spdif_master.id.iface = SND_CONTROL_IFACE_PCM;
strcpy(spdif_output.id.name, "Delta S/PDIF Output Defaults");
}
void hardware_postinit(void)
{
master_clock_update();
volume_change_rate_update();
spdif_input_update();
spdif_output_update();
}

229
envy24control/levelmeters.c Normal file
View file

@ -0,0 +1,229 @@
/*****************************************************************************
levelmeters.c - Stereo level meters
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include "envy24control.h"
static GdkGC *penGreenShadow[21] = { NULL, };
static GdkGC *penGreenLight[21] = { NULL, };
static GdkGC *penOrangeShadow[21] = { NULL, };
static GdkGC *penOrangeLight[21] = { NULL, };
static GdkGC *penRedShadow[21] = { NULL, };
static GdkGC *penRedLight[21] = { NULL, };
static GdkPixmap *pixmap[21] = { NULL, };
static snd_control_t peaks;
static void update_peak_switch(void)
{
int err;
memset(&peaks, 0, sizeof(peaks));
peaks.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(peaks.id.name, "Multi Track Peak");
if ((err = snd_ctl_cread(card_ctl, &peaks)) < 0)
g_print("Unable to read peaks: %s\n", snd_strerror(err));
}
static void get_levels(int idx, int *l1, int *l2)
{
*l1 = *l2 = 0;
if (idx == 0) {
*l1 = peaks.value.integer.value[4 + 20];
*l2 = peaks.value.integer.value[4 + 21];
} else {
*l1 = *l2 = peaks.value.integer.value[4 + idx - 1];
}
}
static GdkGC *get_pen(int idx, int nRed, int nGreen, int nBlue)
{
GdkColor *c;
GdkGC *gc;
c = (GdkColor *)g_malloc(sizeof(GdkColor));
c->red = nRed;
c->green = nGreen;
c->blue = nBlue;
gdk_color_alloc(gdk_colormap_get_system(), c);
gc = gdk_gc_new(pixmap[idx]);
gdk_gc_set_foreground(gc, c);
return gc;
}
static int get_index(gchar *name)
{
int result;
if (!strcmp(name, "DigitalMixer"))
return 0;
result = atoi(name + 5);
if (result < 1 || result > 20) {
g_print("Wrong drawing area ID: %s\n", name);
gtk_main_quit();
}
return result;
}
static void redraw_meters(int idx, int width, int height, int level1, int level2)
{
int stereo = idx == 0;
int segment_width = stereo ? (width / 2) - 8 : width - 12;
int segments = (height - 6) / 4;
int green_segments = (segments / 4) * 3;
int red_segments = 2;
int orange_segments = segments - green_segments - red_segments;
int seg;
int segs_on1 = ((segments * level1) + 128) / 255;
int segs_on2 = ((segments * level2) + 128) / 255;
// g_print("segs_on1 = %i (%i), segs_on2 = %i (%i)\n", segs_on1, level1, segs_on2, level2);
for (seg = 0; seg < green_segments; seg++) {
gdk_draw_rectangle(pixmap[idx],
segs_on1 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
TRUE,
6, 3 + ((segments - seg - 1) * 4),
segment_width,
3);
if (stereo)
gdk_draw_rectangle(pixmap[idx],
segs_on2 > 0 ? penGreenLight[idx] : penGreenShadow[idx],
TRUE,
2 + (width / 2),
3 + ((segments - seg - 1) * 4),
segment_width,
3);
segs_on1--;
segs_on2--;
}
for (seg = green_segments; seg < green_segments + orange_segments; seg++) {
gdk_draw_rectangle(pixmap[idx],
segs_on1 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
TRUE,
6, 3 + ((segments - seg - 1) * 4),
segment_width,
3);
if (stereo)
gdk_draw_rectangle(pixmap[idx],
segs_on2 > 0 ? penOrangeLight[idx] : penOrangeShadow[idx],
TRUE,
2 + (width / 2),
3 + ((segments - seg - 1) * 4),
segment_width,
3);
segs_on1--;
segs_on2--;
}
for (seg = green_segments + orange_segments; seg < segments; seg++) {
gdk_draw_rectangle(pixmap[idx],
segs_on1 > 0 ? penRedLight[idx] : penRedShadow[idx],
TRUE,
6, 3 + ((segments - seg - 1) * 4),
segment_width,
3);
if (stereo)
gdk_draw_rectangle(pixmap[idx],
segs_on2 > 0 ? penRedLight[idx] : penRedShadow[idx],
TRUE,
2 + (width / 2),
3 + ((segments - seg - 1) * 4),
segment_width,
3);
segs_on1--;
segs_on2--;
}
}
gint level_meters_configure_event(GtkWidget *widget, GdkEventConfigure *event)
{
int idx = get_index(gtk_widget_get_name(widget));
if (pixmap[idx] != NULL)
gdk_pixmap_unref(pixmap[idx]);
pixmap[idx] = gdk_pixmap_new(widget->window,
widget->allocation.width,
widget->allocation.height,
-1);
penGreenShadow[idx] = get_pen(idx, 0, 0x77ff, 0);
penGreenLight[idx] = get_pen(idx, 0, 0xffff, 0);
penOrangeShadow[idx] = get_pen(idx, 0xddff, 0x55ff, 0);
penOrangeLight[idx] = get_pen(idx, 0xffff, 0x99ff, 0);
penRedShadow[idx] = get_pen(idx, 0xaaff, 0, 0);
penRedLight[idx] = get_pen(idx, 0xffff, 0, 0);
gdk_draw_rectangle(pixmap[idx],
widget->style->black_gc,
TRUE,
0, 0,
widget->allocation.width,
widget->allocation.height);
// g_print("configure: %i:%i\n", widget->allocation.width, widget->allocation.height);
redraw_meters(idx, widget->allocation.width, widget->allocation.height, 0, 0);
return TRUE;
}
gint level_meters_expose_event(GtkWidget *widget, GdkEventExpose *event)
{
int idx = get_index(gtk_widget_get_name(widget));
int l1, l2;
get_levels(idx, &l1, &l2);
redraw_meters(idx, widget->allocation.width, widget->allocation.height, l1, l2);
gdk_draw_pixmap(widget->window,
widget->style->black_gc,
pixmap[idx],
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
gint level_meters_timeout_callback(gpointer data)
{
GtkWidget *widget;
int idx, l1, l2;
update_peak_switch();
for (idx = 0; idx <= 20; idx++) {
get_levels(idx, &l1, &l2);
widget = idx == 0 ? mixer_mix_drawing : mixer_drawing[idx-1];
if (!GTK_WIDGET_VISIBLE(widget))
continue;
redraw_meters(idx, widget->allocation.width, widget->allocation.height, l1, l2);
gdk_draw_pixmap(widget->window,
widget->style->black_gc,
pixmap[idx],
0, 0,
0, 0,
widget->allocation.width, widget->allocation.height);
}
return TRUE;
}
void level_meters_reset_peaks(GtkButton *button, gpointer data)
{
}
void level_meters_init(void)
{
memset(&peaks, 0, sizeof(peaks));
}
void level_meters_postinit(void)
{
level_meters_timeout_callback(NULL);
}

188
envy24control/mixer.c Normal file
View file

@ -0,0 +1,188 @@
/*****************************************************************************
mixer.c - mixer code
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include "envy24control.h"
#define toggle_set(widget, state) \
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
static int is_active(GtkWidget *widget)
{
return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
}
void mixer_update_stream(int stream, int vol_flag, int sw_flag)
{
snd_control_t vol, sw;
int err;
if (vol_flag) {
memset(&vol, 0, sizeof(vol));
vol.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(vol.id.name, stream <= 10 ? "Multi Playback Volume" : "Multi Capture Volume");
vol.id.index = (stream - 1) % 10;
if ((err = snd_ctl_cread(card_ctl, &vol)) < 0)
g_print("Unable to read multi playback volume: %s\n", snd_strerror(err));
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), 96 - vol.value.integer.value[0]);
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), 96 - vol.value.integer.value[1]);
if (vol.value.integer.value[0] != vol.value.integer.value[1])
toggle_set(mixer_stereo_toggle[stream-1], FALSE);
}
if (sw_flag) {
memset(&sw, 0, sizeof(sw));
sw.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(sw.id.name, stream <= 10 ? "Multi Playback Switch" : "Multi Capture Switch");
sw.id.index = (stream - 1) % 10;
if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
g_print("Unable to read multi playback switch: %s\n", snd_strerror(err));
toggle_set(mixer_solo_toggle[stream-1][0], sw.value.integer.value[0] ? TRUE : FALSE);
toggle_set(mixer_solo_toggle[stream-1][1], sw.value.integer.value[1] ? TRUE : FALSE);
toggle_set(mixer_mute_toggle[stream-1][0], !sw.value.integer.value[0] ? TRUE : FALSE);
toggle_set(mixer_mute_toggle[stream-1][1], !sw.value.integer.value[1] ? TRUE : FALSE);
if (sw.value.integer.value[0] != sw.value.integer.value[1])
toggle_set(mixer_stereo_toggle[stream-1], FALSE);
}
}
static void set_switch1(int stream, int left, int right)
{
snd_control_t sw;
int err;
memset(&sw, 0, sizeof(sw));
sw.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(sw.id.name, stream <= 10 ? "Multi Playback Switch" : "Multi Capture Switch");
sw.id.index = (stream - 1) % 10;
if ((err = snd_ctl_cread(card_ctl, &sw)) < 0)
g_print("Unable to read multi switch: %s\n", snd_strerror(err));
if (left >= 0)
sw.value.integer.value[0] = left != 0;
if (right >= 0)
sw.value.integer.value[1] = right != 0;
if ((err = snd_ctl_cwrite(card_ctl, &sw)) < 0 && err != -EBUSY)
g_print("Unable to write multi switch: %s\n", snd_strerror(err));
}
void mixer_toggled_solo(GtkWidget *togglebutton, gpointer data)
{
int stream = (long)data >> 16;
int button = (long)data & 1;
int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
int vol[2] = { -1, -1 };
if (is_active(togglebutton)) {
if (is_active(mixer_mute_toggle[stream-1][button]))
toggle_set(mixer_mute_toggle[stream-1][button], FALSE);
vol[button] = 1;
if (stereo) {
if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
vol[button ^ 1] = 1;
}
} else {
if (!is_active(mixer_mute_toggle[stream-1][button]))
toggle_set(mixer_mute_toggle[stream-1][button], TRUE);
vol[button] = 0;
if (stereo) {
if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
vol[button ^ 1] = 0;
}
}
set_switch1(stream, vol[0], vol[1]);
}
void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data)
{
int stream = (long)data >> 16;
int button = (long)data & 1;
int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
int vol[2] = { -1, -1 };
if (is_active(togglebutton)) {
if (is_active(mixer_solo_toggle[stream-1][button]))
toggle_set(mixer_solo_toggle[stream-1][button], FALSE);
vol[button] = 0;
if (stereo) {
if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
vol[button ^ 1] = 0;
}
} else {
if (!is_active(mixer_solo_toggle[stream-1][button]))
toggle_set(mixer_solo_toggle[stream-1][button], TRUE);
vol[button] = 1;
if (stereo) {
if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
vol[button ^ 1] = 1;
}
}
set_switch1(stream, vol[0], vol[1]);
}
static void set_volume1(int stream, int left, int right)
{
snd_control_t vol;
int err;
memset(&vol, 0, sizeof(vol));
vol.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(vol.id.name, stream <= 10 ? "Multi Playback Volume" : "Multi Capture Volume");
vol.id.index = (stream - 1) % 10;
if ((err = snd_ctl_cread(card_ctl, &vol)) < 0)
g_print("Unable to read multi volume: %s\n", snd_strerror(err));
if (left >= 0)
vol.value.integer.value[0] = left;
if (right >= 0)
vol.value.integer.value[1] = right;
if ((err = snd_ctl_cwrite(card_ctl, &vol)) < 0 && err != -EBUSY)
g_print("Unable to write multi volume: %s\n", snd_strerror(err));
}
void mixer_adjust(GtkAdjustment *adj, gpointer data)
{
int stream = (long)data >> 16;
int button = (long)data & 1;
int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
int vol[2] = { -1, -1 };
vol[button] = 96 - adj->value;
if (stereo) {
gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][button ^ 1]), adj->value);
vol[button ^ 1] = 96 - adj->value;
}
set_volume1(stream, vol[0], vol[1]);
}
void mixer_postinit(void)
{
int stream;
for (stream = 1; stream <= 20; stream++)
mixer_update_stream(stream, 1, 1);
}

195
envy24control/patchbay.c Normal file
View file

@ -0,0 +1,195 @@
/*****************************************************************************
patchbay.c - patchbay/router code
Copyright (C) 2000 by Jaroslav Kysela <perex@suse.cz>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/
#include "envy24control.h"
static snd_control_t routes;
#define toggle_set(widget, state) \
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
static int is_active(GtkWidget *widget)
{
return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
}
static int get_toggle_index(int stream)
{
unsigned short psdout = routes.value.bytes.data[0] |
(routes.value.bytes.data[1] << 8);
unsigned short spdout = routes.value.bytes.data[2] |
(routes.value.bytes.data[3] << 8);
unsigned int capture = routes.value.bytes.data[4] |
(routes.value.bytes.data[5] << 8) |
(routes.value.bytes.data[6] << 16) |
(routes.value.bytes.data[7] << 24);
int right = (stream - 1) & 1;
int source = (stream - 1) >> 1;
stream--;
if (stream < 0 || stream > 9) {
g_print("get_toggle_index (1)\n");
return 0;
}
if (stream < 8) { /* SPDOUT */
int psdout_shift = (source << 1) + (right ? 8 : 0);
int capture_shift = (source << 3) + (right ? 4 : 0);
int setup = (psdout >> psdout_shift) & 3;
int csetup = (capture >> capture_shift) & 15;
switch (setup) {
case 0: /* PCM Out */
return 0;
case 1: /* digital mixer */
if (stream == 0 || stream == 1)
return 1;
return 0;
case 2:
return (csetup & 7) + 4;
case 3:
if (csetup & 8)
return 3; /* S/PDIF right */
return 2; /* S/PDIF left */
}
} else { /* SPDOUT */
int spdout_shift = right ? 2 : 0;
int spdout_shift1 = right ? 12 : 8;
int setup = (spdout >> spdout_shift) & 3;
int setup1 = (spdout >> spdout_shift1) & 15;
switch (setup) {
case 0: /* PCM Out */
return 0;
case 1: /* digital mixer */
if (stream == 0 || stream == 1)
return 1;
return 0;
case 2:
return (setup1 & 7) + 4;
case 3:
if (setup1 & 8)
return 3; /* S/PDIF right */
return 2; /* S/PDIF left */
}
}
return 0;
}
void patchbay_update(void)
{
int stream, tidx, err;
if ((err = snd_ctl_cread(card_ctl, &routes)) < 0) {
g_print("Multi track routes read error: %s\n", snd_strerror(err));
return;
}
for (stream = 1; stream <= 10; stream++) {
tidx = get_toggle_index(stream);
toggle_set(router_radio[stream - 1][tidx], TRUE);
}
}
static void set_routes(int stream, int idx)
{
unsigned short psdout = routes.value.bytes.data[0] |
(routes.value.bytes.data[1] << 8);
unsigned short spdout = routes.value.bytes.data[2] |
(routes.value.bytes.data[3] << 8);
unsigned int capture = routes.value.bytes.data[4] |
(routes.value.bytes.data[5] << 8) |
(routes.value.bytes.data[6] << 16) |
(routes.value.bytes.data[7] << 24);
int right = (stream - 1) & 1;
int source = (stream - 1) >> 1;
int err;
stream--;
if (stream < 0 || stream > 9) {
g_print("set_routes (1)\n");
return;
}
if (stream < 8) { /* SPDOUT */
int psdout_shift = (source << 1) + (right ? 8 : 0);
int capture_shift = (source << 3) + (right ? 4 : 0);
psdout &= ~(3 << psdout_shift);
if (idx == 0) { /* PCM Out */
/* nothing */ ;
} else if (idx == 1) { /* digital mixer */
if (stream == 0 || stream == 1)
psdout |= 1 << psdout_shift;
} else if (idx == 2 || idx == 3) { /* S/PDIF left & right */
psdout |= 3 << psdout_shift;
capture &= ~(1 << (capture_shift + 3));
capture |= (idx - 2) << (capture_shift + 3);
} else {
psdout |= 2 << psdout_shift;
capture &= ~(7 << capture_shift);
capture |= ((idx - 4) & 7) << capture_shift;
}
} else { /* SPDOUT */
int spdout_shift = right ? 2 : 0;
int spdout_shift1 = right ? 12 : 8;
spdout &= ~(3 << spdout_shift);
if (idx == 0) { /* PCM Out 9 & 10 */
/* nothing */ ;
} else if (idx == 1) { /* digital mixer */
spdout |= 1 << spdout_shift;
} else if (idx == 2 || idx == 3) { /* S/PDIF left & right */
spdout |= 3 << spdout_shift;
spdout &= ~(1 << (spdout_shift1 + 3));
spdout |= (idx - 2) << (spdout_shift1 + 3);
} else {
spdout |= 2 << spdout_shift;
spdout &= ~(7 << spdout_shift1);
spdout |= ((idx - 4) & 7) << spdout_shift1;
}
}
routes.value.bytes.data[0] = psdout & 0xff;
routes.value.bytes.data[1] = (psdout >> 8) & 0xff;
routes.value.bytes.data[2] = spdout & 0xff;
routes.value.bytes.data[3] = (spdout >> 8) & 0xff;
routes.value.bytes.data[4] = capture & 0xff;
routes.value.bytes.data[5] = (capture >> 8) & 0xff;
routes.value.bytes.data[6] = (capture >> 16) & 0xff;
routes.value.bytes.data[7] = (capture >> 24) & 0xff;
// g_print("psdout = 0x%x, spdout = 0x%x, capture = 0x%x\n", psdout, spdout, capture);
if ((err = snd_ctl_cwrite(card_ctl, &routes)) < 0)
g_print("Multi track route write error: %s\n", snd_strerror(err));
}
void patchbay_toggled(GtkWidget *togglebutton, gpointer data)
{
int stream = (long)data >> 16;
int what = (long)data & 0xffff;
if (is_active(togglebutton))
set_routes(stream, what);
}
void patchbay_init(void)
{
memset(&routes, 0, sizeof(routes));
routes.id.iface = SND_CONTROL_IFACE_MIXER;
strcpy(routes.id.name, "Multi Track Route");
}
void patchbay_postinit(void)
{
patchbay_update();
}