480 lines
7.7 KiB
C
480 lines
7.7 KiB
C
/*
|
|
* wmmp3
|
|
* Copyright (c)1999 Patrick Crosby <xb@dotfiles.com>.
|
|
* This software covered by the GPL. See COPYING file for details.
|
|
*
|
|
* mpg123ctl.c
|
|
*
|
|
* This file contains all the functions for controlling the
|
|
* mpg123 backend processes.
|
|
*
|
|
* Random play functionality courtesy of:
|
|
* Matthew D. Campbell <matt@campbellhome.dhs.org>
|
|
*
|
|
* $Id: mpg123ctl.c,v 1.15 1999/10/12 04:41:20 pcrosby Exp $
|
|
*/
|
|
|
|
#include "mpg123ctl.h"
|
|
|
|
#define MAXDIRS 100
|
|
#define MAX_TITLE_LEN 9
|
|
|
|
void set_playlist();
|
|
void signal_play();
|
|
void play();
|
|
void play_next();
|
|
void play_prev();
|
|
void init_ctl();
|
|
void push_dir(char *s);
|
|
void push_dirname(char *s);
|
|
char *pop_dir();
|
|
char *next_mp3dir();
|
|
char *prev_mp3dir();
|
|
char *current_mp3dir();
|
|
void show_directory_name();
|
|
void load_next_dir();
|
|
void load_prev_dir();
|
|
void alarmhandler(int sig);
|
|
void scroll_title();
|
|
void finish();
|
|
void dostuff();
|
|
|
|
char *dirs[MAXDIRS];
|
|
int top = 0;
|
|
int max_dirs = 0;
|
|
int current_dir = 0;
|
|
|
|
char *dirnames[MAXDIRS];
|
|
int ntop = 0;
|
|
int nmax_dirs = 0;
|
|
|
|
char mpg123_cmd[512];
|
|
char mp3ext[12];
|
|
char playlistext[12];
|
|
|
|
int next_song = 0;
|
|
int num_songs = 0;
|
|
int play_pid = 0;
|
|
|
|
char title[512];
|
|
int scroll_pos = 0;
|
|
int do_scroll = 0;
|
|
int always_scroll = 0;
|
|
|
|
int repeat_flag = 0;
|
|
int random_flag = 0;
|
|
int *rand_song_num = NULL;
|
|
|
|
int is_playing()
|
|
{
|
|
if (play_pid > 0)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* patch received from Steven Jorgensen to fix following function
|
|
*/
|
|
|
|
void set_playlist()
|
|
{
|
|
char *directory;
|
|
DIR *dp;
|
|
struct dirent *entry;
|
|
char filename[512];
|
|
|
|
int i, tempnum, temppos;
|
|
|
|
directory = (char *) current_mp3dir();
|
|
|
|
if (directory)
|
|
{
|
|
dp = opendir(directory);
|
|
if (dp == NULL) {
|
|
char *new_directory;
|
|
new_directory = (char *) next_mp3dir();
|
|
dp = opendir(new_directory);
|
|
while (new_directory && (strcmp(new_directory, directory) != 0) &&
|
|
(dp == NULL)) {
|
|
strcpy(directory, new_directory);
|
|
new_directory = (char *) next_mp3dir();
|
|
dp = opendir(new_directory);
|
|
}
|
|
if (new_directory)
|
|
strcpy(directory, new_directory);
|
|
}
|
|
if (dp != NULL) {
|
|
show_directory_name();
|
|
num_songs = 0;
|
|
empty_hash();
|
|
entry = readdir(dp);
|
|
while (entry != NULL) {
|
|
if (strstr(entry->d_name, mp3ext)) {
|
|
sprintf(filename, "%s/%s", directory, entry->d_name);
|
|
insert_song(num_songs, entry->d_name, filename);
|
|
num_songs++;
|
|
}
|
|
entry = readdir(dp);
|
|
}
|
|
next_song = 0;
|
|
|
|
/* Create Pseudo-random permutation of list */
|
|
srand(time(NULL));
|
|
rand_song_num = (int *)malloc(sizeof(int)*num_songs);
|
|
if (!rand_song_num) {
|
|
/* This shouldn't happen - the list isn't that big */
|
|
fprintf(stderr,
|
|
"Error: cannot allocate randomized list\n");
|
|
exit(1);
|
|
}
|
|
for (i=0; i<num_songs; i++) rand_song_num[i] = i;
|
|
for (i=0; i<num_songs; i++) {
|
|
tempnum = rand_song_num[i];
|
|
temppos = rand()%num_songs;
|
|
rand_song_num[i] = rand_song_num[temppos];
|
|
rand_song_num[temppos] = tempnum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* functions that actually control mpg123
|
|
*/
|
|
|
|
void signal_play()
|
|
{
|
|
int status;
|
|
|
|
waitpid(play_pid, &status, 0);
|
|
play_pid = 0;
|
|
play_next();
|
|
}
|
|
|
|
void play(char *song_name)
|
|
{
|
|
if ((play_pid = fork()) == 0) {
|
|
execl(mpg123_cmd, mpg123_cmd, "-q",
|
|
song_name, 0);
|
|
_exit(1);
|
|
}
|
|
}
|
|
|
|
void play_next()
|
|
{
|
|
struct hash_elt *song;
|
|
|
|
if (next_song >= num_songs) {
|
|
if (repeat_flag == 0) {
|
|
load_next_dir();
|
|
} else {
|
|
next_song = 0;
|
|
}
|
|
}
|
|
song = get_song(next_song);
|
|
if (random_flag) {
|
|
song = get_song(rand_song_num[next_song]);
|
|
}
|
|
if (song) {
|
|
strcpy(title, song->title);
|
|
strcat(title, " ");
|
|
scroll_pos = 0;
|
|
do_scroll = 1;
|
|
scroll_title();
|
|
|
|
play(song->filename);
|
|
next_song++;
|
|
signal(SIGCHLD, signal_play);
|
|
signal(SIGALRM, alarmhandler);
|
|
alarm(1);
|
|
}
|
|
}
|
|
|
|
void play_prev()
|
|
{
|
|
struct hash_elt *song;
|
|
|
|
if (next_song <= 1) {
|
|
next_song = 0;
|
|
}
|
|
else {
|
|
next_song = next_song - 2;
|
|
}
|
|
|
|
play_next();
|
|
}
|
|
|
|
void user_play()
|
|
{
|
|
if (play_pid == 0) {
|
|
signal(SIGCHLD, signal_play);
|
|
set_playlist();
|
|
play_next();
|
|
}
|
|
}
|
|
|
|
void stop()
|
|
{
|
|
int status;
|
|
|
|
if (play_pid > 0) {
|
|
signal(SIGCHLD, SIG_IGN);
|
|
kill(play_pid, SIGINT);
|
|
kill(play_pid, SIGTERM);
|
|
kill(play_pid, SIGKILL);
|
|
waitpid(play_pid, &status, 0);
|
|
play_pid = 0;
|
|
}
|
|
}
|
|
|
|
void next()
|
|
{
|
|
stop();
|
|
play_next();
|
|
}
|
|
|
|
void back()
|
|
{
|
|
stop();
|
|
play_prev();
|
|
}
|
|
|
|
/*
|
|
* initialization functions
|
|
*/
|
|
|
|
void init_ctl()
|
|
{
|
|
signal(SIGINT, finish);
|
|
signal(SIGCHLD, dostuff);
|
|
set_playlist();
|
|
}
|
|
|
|
void set_mpg123(char *s)
|
|
{
|
|
|
|
strcpy(mpg123_cmd, s);
|
|
}
|
|
|
|
void set_mp3ext(char *s)
|
|
{
|
|
strcpy(mp3ext, s);
|
|
}
|
|
|
|
void set_playlistext(char *s)
|
|
{
|
|
strcpy(playlistext, s);
|
|
}
|
|
|
|
void set_alwaysscroll(char *s) {
|
|
char *temp = s;
|
|
while (*temp) {
|
|
*temp = tolower(*temp);
|
|
temp++;
|
|
}
|
|
if ( !strcmp(s, "on") || !strcmp(s, "yes") || !strcmp(s, "1") ||
|
|
!strcmp(s, "true")) {
|
|
always_scroll = 1;
|
|
} else {
|
|
always_scroll = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void push_dir(char *s)
|
|
{
|
|
dirs[top] = (char *) malloc(strlen(s) + 1);
|
|
strcpy(dirs[top], s);
|
|
top++;
|
|
max_dirs++;
|
|
}
|
|
|
|
void push_dirname(char *s)
|
|
{
|
|
/* from Steven Jorgensen */
|
|
if ((strlen(s) + 1) < 10)
|
|
dirnames[ntop] = (char *) malloc(10);
|
|
else
|
|
dirnames[ntop] = (char *) malloc(strlen(s) + 1);
|
|
strcpy(dirnames[ntop], s);
|
|
ntop++;
|
|
nmax_dirs++;
|
|
}
|
|
|
|
char *pop_dir()
|
|
{
|
|
max_dirs--;
|
|
return (dirs[top--]);
|
|
}
|
|
|
|
void add_mp3dir(char *s)
|
|
{
|
|
push_dir(s);
|
|
}
|
|
|
|
void add_mp3dirname(char *s)
|
|
{
|
|
push_dirname(s);
|
|
}
|
|
|
|
/*
|
|
* directory manipulation
|
|
*/
|
|
|
|
char *next_mp3dir()
|
|
{
|
|
if (current_dir < (max_dirs - 1)) {
|
|
current_dir++;
|
|
}
|
|
return (dirs[current_dir]);
|
|
}
|
|
|
|
char *prev_mp3dir()
|
|
{
|
|
if (current_dir > 0) {
|
|
current_dir--;
|
|
}
|
|
return (dirs[current_dir]);
|
|
}
|
|
|
|
char *current_mp3dir()
|
|
{
|
|
return (dirs[current_dir]);
|
|
}
|
|
|
|
void show_directory_name()
|
|
{
|
|
if (dirnames[current_dir] != NULL) {
|
|
while (strlen(dirnames[current_dir]) < 9) {
|
|
strcat(dirnames[current_dir], " ");
|
|
}
|
|
draw_string(dirnames[current_dir], 5, 5);
|
|
} else {
|
|
draw_string("no dirname", 5, 5);
|
|
}
|
|
}
|
|
|
|
void dir_up(int button_num)
|
|
{
|
|
if (!is_playing()) {
|
|
button_down(button_num);
|
|
load_prev_dir();
|
|
}
|
|
}
|
|
|
|
void dir_down(int button_num)
|
|
{
|
|
if (!is_playing()) {
|
|
button_down(button_num);
|
|
load_next_dir();
|
|
}
|
|
}
|
|
|
|
void load_next_dir()
|
|
{
|
|
next_mp3dir();
|
|
set_playlist();
|
|
}
|
|
|
|
void load_prev_dir()
|
|
{
|
|
prev_mp3dir();
|
|
set_playlist();
|
|
}
|
|
|
|
/*
|
|
* song title functions
|
|
*/
|
|
|
|
void alarmhandler(int sig)
|
|
{
|
|
if ((play_pid > 0) && (do_scroll == 1)) {
|
|
scroll_title();
|
|
signal(SIGALRM, alarmhandler);
|
|
alarm(1);
|
|
}
|
|
}
|
|
|
|
void scroll_title()
|
|
{
|
|
char s[MAX_TITLE_LEN + 1];
|
|
int i;
|
|
int title_len;
|
|
|
|
title_len = strlen(title);
|
|
if (do_scroll) {
|
|
for (i = 0; i < MAX_TITLE_LEN; i++) {
|
|
s[i] = title[(i + scroll_pos) % title_len];
|
|
}
|
|
s[i] = '\0';
|
|
draw_string(s, 5, 19);
|
|
scroll_pos++;
|
|
if (scroll_pos > title_len) {
|
|
scroll_pos = 0;
|
|
if (!always_scroll) {
|
|
do_scroll = 0;
|
|
}
|
|
}
|
|
} else {
|
|
draw_string(title, 5, 19);
|
|
}
|
|
RedrawWindow();
|
|
}
|
|
|
|
void turn_on_scroll()
|
|
{
|
|
if ((!do_scroll) && (is_playing())) {
|
|
do_scroll = 1;
|
|
scroll_pos = 0;
|
|
signal(SIGALRM, alarmhandler);
|
|
alarm(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* toggles
|
|
*/
|
|
|
|
void random_toggle(int button_num)
|
|
{
|
|
/* button_gray(button_num); */
|
|
if (random_flag == 0) {
|
|
button_down(button_num);
|
|
random_flag = 1;
|
|
} else {
|
|
button_up(button_num);
|
|
random_flag = 0;
|
|
}
|
|
}
|
|
|
|
void repeat_toggle(int button_num)
|
|
{
|
|
if (repeat_flag == 0) {
|
|
button_down(button_num);
|
|
repeat_flag = 1;
|
|
} else {
|
|
button_up(button_num);
|
|
repeat_flag = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* cleanup
|
|
*/
|
|
|
|
void finish()
|
|
{
|
|
stop();
|
|
}
|
|
|
|
/*
|
|
* misc
|
|
*/
|
|
void dostuff()
|
|
{
|
|
/* empty */
|
|
}
|
|
|