setvol.c

Posted by: mlord

setvol.c - 06/06/2002 12:58

Dunno if anyone else has bothered before, but here is a small C program to set the volume level on a RioCar/Empeg player.

This is useful when attempting to play sounds prior to the player having started up, especially when Hijack is installed since Hijack zeros the volume controls at init time.

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

#define MIXER "/dev/mixer"

int main(int argc, char *argv[])
{
int fd;
int vol = -1;

if (argc != 2 || (vol = atoi(argv[1])) < 0 || vol > 100) {
fprintf(stderr, "Usage: %s volume (where 0 <= volume <= 100)\n", argv[0]);
exit(1);
}

fd = open(MIXER, O_WRONLY);
if (fd == -1) {
perror(MIXER);
exit(1);
}

vol |= (vol << 8);
if (ioctl(fd, SOUND_MIXER_WRITE_VOLUME, &vol) == -1) {
perror("SOUND_MIXER_WRITE_VOLUME");
exit(-1);
}
close(fd);
printf("Volume=%d\n", vol & 0xff);
exit(0);
}
Posted by: drakino

Re: setvol.c - 09/06/2002 09:07

Very useful, thanks. I am helping someone here shortly to add a startup sound to their unit. I ran into problems when I realised the volume was muted at boot, instead of being at 0db like it was when I last did this.

If anyone is up for enhancing this, my main suggestion is to add a way of setting the volume to the last known value of the car or home volume.
Posted by: mlord

Re: setvol.c - 09/06/2002 09:25

By the time you run setvol, the disks are up and spinning, and the savearea has been read in by the kernel.

So.. write a shell script (or modify setvol.c) to read the SaveBase value from /proc/empeg_state, and then seek to that location in /dev/kmem and read the savearea. Then extract the saved vol level from the savearea, taking into account car/home modes, and you're all set. Simple, huh?

-ml
Posted by: mlord

Re: setvol.c - 09/06/2002 09:29

Or simpler: do a read() from /dev/empeg_state to retrieve the state. Still gotta get the current power mode (AC/DC) from /proc/empeg_power, and then pull the correct volume setting from the corresponding offset within the savearea.

To figure out the volume location in the savearea, use the Hijack menu item for "Show Flash Savearea" to scroll around while you adjust the volume to see which part of it changes (it gets hilighted). Repeat for the "other" power mode to cover both AC/DC.

This could be a useful app.. go for it!

-ml
Posted by: mlord

New improved(!) setvol.c - 09/06/2002 10:20

Okay, this version of setvol (Empeg executable is attached, source is below) now restores the previous "saved" volume level (AC or DC) when run without any arguments. Otherwise, it takes a parameter 0..100 as before.

Enjoy!

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

#define MIXER "/dev/mixer"
#define STATE "/dev/empeg_state"
#define POWER "/proc/empeg_power"

static int Open (const char *path, int mode)
{
int fd = open(path, mode);
if (fd == -1) {
perror(path);
exit(errno);
}
return fd;
}

int main(int argc, char *argv[])
{
int fd;
int vol = -1;

if (argc == 1) {
unsigned char state[128], on_dc;
// restore previous level for this powermode
fd = Open(STATE, O_RDONLY);
if (sizeof(state) != read(fd, state, sizeof(state))) {
perror(STATE);
exit(errno);
}
close(fd);
fd = Open(POWER, O_RDONLY);
if (1 != read(fd, &on_dc, 1)) {
perror(POWER);
exit(errno);
}
close(fd);
on_dc &= 1;
if (on_dc)
vol = (state[0x0d] >> 1);
else
vol = ((state[0x0d] & 1) << 6) | (state[0xc] >> 2);
printf("Saved %s volume was %u\n", on_dc ? "DC" : "AC", vol);
} else if (argc != 2 || (vol = atoi(argv[1])) < 0 || vol > 100) {
fprintf(stderr, "Usage: %s volume (where 0 <= volume <= 100)\n", argv[0]);
exit(-1);
}

fd = Open(MIXER, O_WRONLY);
vol |= (vol << 8);
if (ioctl(fd, SOUND_MIXER_WRITE_VOLUME, &vol) == -1) {
perror("SOUND_MIXER_WRITE_VOLUME");
exit(errno);
}
close(fd);
printf("Volume=%d\n", vol & 0xff);
exit(0);
}
Posted by: drakino

Re: New improved(!) setvol.c - 09/06/2002 14:28

Thanks again. My experience with pure C is still nothing beyond "Hello World" (And my last attempt segfaulted).
Posted by: mlord

Re: New improved(!) setvol.c - 09/06/2002 17:12

You're welcome. Just keep in mind that it restores the volume level of the last power-on, not the "most recent" volume level, if different.

Cheers
Posted by: mcomb

Re: setvol.c - 09/06/2002 20:22

I though Mark writing userland stuff was one of the sings of the coming apocalypse? Should I be stocking up on ammo and canned food?

:-)
Posted by: tonyc

Re: setvol.c - 09/06/2002 20:51

I though Mark writing userland stuff was one of the sings of the coming apocalypse?

Well, hey, I'm sure even Tiger Woods feels the urge to hit the mini-putt course now and then...
Posted by: mlord

Re: setvol.c - 10/06/2002 06:14

Hey, despite all of my now forgotten work on the Linux kernel, most folks who know my name remember it from "hdparm", a simple ioctl() calling userland utility for controlling the IDE driver. So this setvol thingie is right down that alley for me.

Cheers
Posted by: Caps

Re: setvol.c - Sound During Bootup - 10/07/2002 09:58

Has anybody ever been successful at getting sound to play while the eMpeg is booting up? I was thinking it would be cool to play the THX intro or the other movie sound. There would be a lot of sounds that would work.

I was thinking on how it could be done, and it would have to be very small and accesible very quickly after the power is turned on. A delay of 1-3 seconds would be acceptable, but the sound would have to finish prior to the music starting. This setvol.c code looks promising for getting the volume
turned on, but how would you think I could get the music file to be played very early?

-Thanks

Posted by: tfabris

Re: setvol.c - Sound During Bootup - 10/07/2002 10:21

Yes this has been done. Try searching the BBS on "startup sound".