PDA

View Full Version : [SOLVED] SDL music



qw3rty_rocks
April 10th, 2011, 06:44 AM
I was hoping to be able to make a system in SDL that was able to get the contents of a directory (music) and be able to choose a random file and play it. So far things haven't gone to plan so does anyone have an idea on how i could do this?

slavik
April 10th, 2011, 06:47 AM
use gstreamer instead

qw3rty_rocks
April 10th, 2011, 06:53 AM
Well I had already got music working already and i don't really want to switch to gstreamer but I want to be able to, lets say, allow the user to drop music in a folder and the program will play whatever is in there automatically. I don't know how to do this.
I'm using sdl because i'm making a game.

Phenax
April 10th, 2011, 06:56 AM
What's the problem? Just use SDL_Mixer and something like the gcc-provided dirent.h for going through directories (If you're using C/C++).

qw3rty_rocks
April 10th, 2011, 06:58 AM
Yeah well lets say i was having trouble with dirent.h

Phenax
April 10th, 2011, 07:20 AM
Yeah well lets say i was having trouble with dirent.h

What's your problem? Wikipedia (http://en.wikipedia.org/wiki/Dirent.h#Example) has a good example.

qw3rty_rocks
April 10th, 2011, 07:40 AM
Well i kind of get it but how would i convert the output to work with Mix_LoadMUS();

Phenax
April 10th, 2011, 08:18 AM
Kind of messy, and doesn't handle errors gracefully. Nor does it handle all possible errors. But should give you the general idea. The output of getRandomMusicName(char *path); should be compatible with Mix_LoadMUS. This is C code btw. You'll need to include cstring, cstdlib, ctime instead of what I have if you're using C++.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>

int isMusicFile(char *filename);
char *getRandomMusicName(char *path);

int isMusicFile(char *filename)
{
char extension[4];
strncpy(extension, filename + strlen(filename) - 3, 4);
if(strncmp(extension, "mp3", 3) == 0)
return 1;
else if(strncmp(extension, "ogg", 3) == 0)
return 1;
else if(strncmp(extension, "lac", 3) == 0) //for flac, because im lazy
return 1;

return 0;
}

char *getRandomMusicName(char *path)
{
int i = 0;
char file_names[256][256];

DIR *dp;
struct dirent *entry;

dp = opendir(path);

if(dp == NULL)
perror("opendir");

while((entry = readdir(dp)))
{
if(isMusicFile(entry->d_name))
{
strncpy(file_names[i], entry->d_name, 256);
i++;
}
}

closedir(dp);

if(i == 0)
exit(EXIT_FAILURE); //add your own error handling

//strdup duplicates our string.
//automatic variable are gone from memory
//after the function ends. We need to free this later.
return strdup(file_names[rand() % i]);
}

int main(void)
{
srand(time(NULL));

char *x = getRandomMusicName(".");
if(x == NULL) //our strdup didn't work. insufficient memory, etc.
exit(EXIT_FAILURE);

printf("%s", x);
free(x); //you have to free if you strdup.
return 0;
}

qw3rty_rocks
April 11th, 2011, 05:43 AM
Ok it works, but I want to be able to specify a directory other than the current directory. so lets say a directory "/data/music". I can read the contents of that directory fine. The problem is that when I pass it to Mix_LoadMUS it only gets the name of the file not the directory. How would I fix this?

Phenax
April 11th, 2011, 06:49 AM
So make a (char *) that points to a string containing your path (like char *path = "/data/music/"). Pass that to getRandomMusicName function and set the result to a variable like in the example. Then use something like strncat to concatenate your path and your filename to make a new string that is the full path like "/data/music/file.mp3".

qw3rty_rocks
April 11th, 2011, 07:48 AM
Ok thats what I do but it gives me segmentation fault. Here is the modified code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>

int isMusicFile(char *filename);
char *getRandomMusicName(char *path);

int isMusicFile(char *filename)
{
char extension[4];
strncpy(extension, filename + strlen(filename) - 3, 4);
if(strncmp(extension, "mp3", 3) == 0)
return 1;
else if(strncmp(extension, "ogg", 3) == 0)
return 1;
else if(strncmp(extension, "lac", 3) == 0) //for flac, because im lazy
return 1;

return 0;
}

char *getRandomMusicName(char *path)
{
int i = 0;
char file_names[256][256];

DIR *dp;
struct dirent *entry;

dp = opendir(path);

if(dp == NULL)
perror("opendir");

while((entry = readdir(dp)))
{
if(isMusicFile(entry->d_name))
{
strncpy(file_names[i],path, 256);
i++;
}
}

closedir(dp);

if(i == 0)
exit(EXIT_FAILURE); //add your own error handling

//strdup duplicates our string.
//automatic variable are gone from memory
//after the function ends. We need to free this later.
return strdup(file_names[rand() % i]);
}

int main(void)
{
srand(time(NULL));

char* x = getRandomMusicName("./data/music/");
if(x == NULL) //our strdup didn't work. insufficient memory, etc.
exit(EXIT_FAILURE);
char* path = "./data/music/";
strncat(path, x, 300);

printf("%s", x);
printf("%s", "\n\n");
free(x); //you have to free if you strdup.
return 0;
}

fct
April 11th, 2011, 08:17 AM
You haven't posted where the segfault happens (use gdb) but it might be this:


char* path = "./data/music/";
strncat(path, x, 300);

Phenax
April 11th, 2011, 08:43 AM
You haven't posted where the segfault happens (use gdb) but it might be this:


char* path = "./data/music/";
strncat(path, x, 300);

Indeed.

When you do


char *path = "./data/music";
You cannot actually modify the string that path points to. It allocates a string that contains "./data/music" on the stack, usually it's read-only memory, which is why you get a segmentation fault. Either way, it'd be undefined to do such a thing.
C needs to know the size of things.

Doing


char path[] = "./data/music";
Will give you a modifiable string, meaning you could do something like path[2] = 'b', which would be undefined behavior with the above example, but all this is doing is really becoming


char path[13] = "./data/music";
As "./data/music" is 12 characters long + 1 character for null terminator '\0'
Proof:


#include <stdio.h>

int main(void)
{
char path[] = "./data/music";
printf("%d", sizeof(path)); //a char is ALWAYS 1 byte in C
return 0;
}
Thus you will need to explicitly make path, or a new variable, large enough to hold the path as well as your filename that you will append to it.

qw3rty_rocks
April 11th, 2011, 10:43 AM
IT WORKS!!!!!!!!!!!!!!!!!!!!!!
Yay
Thank you so much you guys.