C SDL2 Mixer Play Wav from pointer - c

So I have an archive that is loading the my .wav files into memory and I am trying to play a .WAV from a void* or handle in memory.
II cannot have all the .wav files in the directory and I have a function that is loading them into memory.
Here is some code that I am trying and I have tried many things , but a lot of it doesn't seem to work and I think that SDL libraries are looking for a physical file to load , but I cannot confirm that.
void *MusicTrack;
void Load_andPlay_music(ntrack){
OpenFileFromMPQ( MusicTracks[ntrack], &MusicTrack) // Opens Audio track from MPQ.
Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096);
music = Mix_LoadMUS(MusicTracks[ntrack]);
// I thought that once the file is loaded it might be available as part of $PATH. This is not the case.
Mix_PlayMusic(music, -1);
}
>
If I try this , ....
Mix_PlayMusic(MusicTrack, -1);
I am met with error
'int Mix_PlayMusic(Mix_Music *,int)': cannot convert argument 1 from 'void *' to 'Mix_Music *'
If you have a better solution using SDL2 then I am willing to look at that too.
Thanks.

Use the (oddly undocumented) Mix_LoadMUS_RW() with a SDL_RWops from SDL_RWFromMem().

I figured this out and it works fine
you can simply do something like this.
You of course might have to change the Mix_openAudio params to meet your needs.
void snd_init()
{
printf("SND INIT\n\n");
// Initialize SDL.
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
printf("ERROR : %s\n\n", SDL_GetError());
}
if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096) < 0) {
printf("SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError());
}
SoundInited = 1;
}
//either some function or something to read the .WAV file into memory and have it gpbuffer point to it.
void * gpbuffer;
void playmusic(){
Mix_Chunk * Music = Mix_QuickLoad_WAV((Uint8* )gpbuffer);
Mix_PlayChannel(2, Music, 0);
}
EDIT I ran into Other problems with this and channels overlapping. So try this out if you need SFX and Music running at the same times.
Mix_OpenAudio(22050, AUDIO_S8, 1, 1024);
SDL_RWops* rw = SDL_RWFromMem(buffer, bytestoread);
Mix_Music* Song = Mix_LoadMUS_RW(rw,1);
Mix_PlayMusic(Song, -1);

Related

How can libzip be used from C to create a zip file in memory?

I am trying to using libzip to create a zip file directly in memory, not to a file on disk. My code is quite basic at the moment as I am getting stuck on creating the necessary zip_t struct from a zip_source_buffer:
#include <stdio.h>
#include <string.h>
#include <zip.h>
int main(int argc, char *arrv[])
{
char buffer[65536] = {};
zip_error_t error;
zip_source_t *zs = zip_source_buffer_create(buffer, sizeof(buffer), 0, &error);
int err = zip_source_begin_write(zs);
printf("%p %d '%s'\n", zs, err, zip_error_strerror(&error));
zip_error_fini(&error);
zip_t * zip = zip_open_from_source(zs, ZIP_CREATE, &error);
printf("%p '%s'\n", zip, zip_error_strerror(&error));
zip_error_fini(&error);
}
the code compiles and runs, but thows an error:
$ ./ztest
0xdd50a0 0 'No error'
(nil) 'Not a zip archive'
It's not clear if the begin_write() is needed, but it doesn't generate an error and I get the same result without it.
What am I missing? Thanks
My 2 cent if anybody yet has interest in question.
Do not forget to zip_source_keep before zip_open_from_source, as zip_close will free source, but we want to use its content.
int flags = 0;
zip_error_t error;
zip_source_t *zsmem = zip_source_buffer_create(0, 0, 0, &error);
//we can fill up new zip with an old one (some template, for example)
if (exdata){
zip_source_begin_write(zsmem);
zip_source_write(zsmem, exdata, exdata_sz);
zip_source_commit_write(zsmem);
}else
flags |= ZIP_TRUNCATE;
zip_source_keep(zsmem); //!!
struct zip* arc = zip_open_from_source(zsmem, flags, &error);
//do more stuff adding, removing files , comments, etc
zip_close(arc);
zip_source_open(zsmem);
zip_source_seek(zsmem, 0, SEEK_END);
zip_int64_t sz = zip_source_tell(zsmem);
zip_source_seek(zsmem, 0, SEEK_SET);
zip_source_read(zsmem, outbuffer, sz);
zip_source_close(zsmem);
zip_source_free(zsmem);
send_over_network(outbuffer);
Use ZIP_TRUNCATE instead of ZIP_CREATE. The archive always exists in the case of a buffer source, so ZIP_CREATE has no effect, but a stream of '0's is not a valid zip file. ZIP_TRUNCATE tells libzip to ignore the buffer's current contents (i.e. override all the '0's with the new archive).
zip_source_begin_write() is called internally by libzip. It's not necessary for it to be called in this kind of situation.

ALSA equivalent to /dev/audio dump?

This will be my poorest question ever...
On an old netbook, I installed an even older version of Debian, and toyed around a bit. One of the rather pleasing results was a very basic MP3 player (using libmpg123), integrated for adding background music to a little application doing something completely different. I grew rather fond of this little solution.
In that program, I dumped the decoded audio (from mpg123_decode()) to /dev/audio via a simple fwrite().
This worked fine - on the netbook.
Now, I came to understand that /dev/audio was something done by OSS, and is no longer supported on newer (ALSA) machines. Sure enough, my laptop (running a current Linux Mint) does not have this device.
So apparently I have to use ALSA instead. Searching the web, I've found a couple of tutorials, and they pretty much blow my mind. Modes, parameters, capabilities, access type, sample format, sample rate, number of channels, number of periods, period size... I understand that ALSA is a powerful API for the ambitious, but that's not what I am looking for (or have the time to grok). All I am looking for is how to play the output of mpg123_decode (the format of which I don't even know, not being an audio geek by a long shot).
Can anybody give me some hints on what needs to be done?
tl;dr
How do I get ALSA to play raw audio data?
There's an OSS compatibility layer for ALSA in the alsa-oss package. Install it and run your program inside the "aoss" program. Or, modprobe the modules listed here:
http://wiki.debian.org/SoundFAQ/#line-105
Then, you'll need to change your program to use "/dev/dsp" or "/dev/dsp0" instead of "/dev/audio". It should work how you remembered... but you might want to cross your fingers just in case.
You could install sox and open a pipe to the play command with the correct samplerate and sample size arguments.
Using ALSA directly is overly complicated, so I hope a Gstreamer solution is fine to you too. Gstreamer gives a nice abstraction to ALSA/OSS/Pulseaudio/you name it -- and is ubiquitous in the Linux world.
I wrote a little library that will open a FILE object where you can fwrite PCM data into:
Gstreamer file. The actual code is less than 100 lines.
Use use it like that:
FILE *output = fopen_gst(rate, channels, bit_depth); // open audio output file
while (have_more_data) fwrite(data, amount, 1, output); // output audio data
fclose(output); // close the output file
I added an mpg123 example, too.
Here is the whole file (in case Github get's out of business ;-) ):
/**
* gstreamer_file.c
* Copyright 2012 René Kijewski <rene.SURNAME#fu-berlin.de>
* License: LGPL 3.0 (http://www.gnu.org/licenses/lgpl-3.0)
*/
#include "gstreamer_file.h"
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <glib.h>
#include <gst/gst.h>
#ifndef _GNU_SOURCE
# error "You need to add -D_GNU_SOURCE to the GCC parameters!"
#endif
/**
* Cookie passed to the callbacks.
*/
typedef struct {
/** { file descriptor to read from, fd to write to } */
int pipefd[2];
/** Gstreamer pipeline */
GstElement *pipeline;
} cookie_t;
static ssize_t write_gst(void *cookie_, const char *buf, size_t size) {
cookie_t *cookie = cookie_;
return write(cookie->pipefd[1], buf, size);
}
static int close_gst(void *cookie_) {
cookie_t *cookie = cookie_;
gst_element_set_state(cookie->pipeline, GST_STATE_NULL); /* we are finished */
gst_object_unref(GST_OBJECT(cookie->pipeline)); /* we won't access the pipeline anymore */
close(cookie->pipefd[0]); /* we won't write anymore */
close(cookie->pipefd[1]); /* we won't read anymore */
free(cookie); /* dispose the cookie */
return 0;
}
FILE *fopen_gst(long rate, int channels, int depth) {
/* initialize Gstreamer */
if (!gst_is_initialized()) {
GError *error;
if (!gst_init_check(NULL, NULL, &error)) {
g_error_free(error);
return NULL;
}
}
/* get a cookie */
cookie_t *cookie = malloc(sizeof(*cookie));
if (!cookie) {
return NULL;
}
/* open a pipe to be used between the caller and the Gstreamer pipeline */
if (pipe(cookie->pipefd) != 0) {
close(cookie->pipefd[0]);
close(cookie->pipefd[1]);
free(cookie);
return NULL;
}
/* set up the pipeline */
char description[256];
snprintf(description, sizeof(description),
"fdsrc fd=%d ! " /* read from a file descriptor */
"audio/x-raw-int, rate=%ld, channels=%d, " /* get PCM data */
"endianness=1234, width=%d, depth=%d, signed=true ! "
"audioconvert ! audioresample ! " /* convert/resample if needed */
"autoaudiosink", /* output to speakers (using ALSA, OSS, Pulseaudio ...) */
cookie->pipefd[0], rate, channels, depth, depth);
cookie->pipeline = gst_parse_launch_full(description, NULL,
GST_PARSE_FLAG_FATAL_ERRORS, NULL);
if (!cookie->pipeline) {
close(cookie->pipefd[0]);
close(cookie->pipefd[1]);
free(cookie);
return NULL;
}
/* open a FILE with specialized write and close functions */
cookie_io_functions_t io_funcs = { NULL, write_gst, NULL, close_gst };
FILE *result = fopencookie(cookie, "w", io_funcs);
if (!result) {
close_gst(cookie);
return NULL;
}
/* start the pipeline (of cause it will wait for some data first) */
gst_element_set_state(cookie->pipeline, GST_STATE_PLAYING);
return result;
}
And ten years later, the "actual" answer is found: That's the wrong way to do it in the first place.
libmpg123 comes with a companion library, libout123, which abstracts the underlying audio system for you. Based on libmpg123 example code:
#include <stdlib.h>
#include "mpg123.h"
#include "out123.h"
int main()
{
mpg123_handle * _mpg_handle;
out123_handle * _out_handle;
double rate, channels, encoding;
size_t position, buffer_size;
unsigned char * buffer;
char filename[] = "Example.mp3";
mpg123_open( _mpg_handle, filename );
mpg123_getformat( _mpg_handle, &rate, &channels, &encoding );
out123_open( _out_handle, NULL, NULL );
mpg123_format_none( _mpg_handle );
mpg123_format( _mpg_handle, rate, channels, encoding );
out123_start( _out_handle, rate, channels, encoding );
buffer_size = mpg123_outblock( _mpg_handle );
buffer = malloc( buffer_size );
do
{
mpg123_read( _mpg_handle, buffer.get(), buffer_size, &position );
out123_play( _out_handle, buffer.get(), position );
} while ( position );
out123_close( _out_handle );
mpg123_close( _mpg_handle );
free( buffer );
}

cvCreateFileCapture strange error

i'm trying to create a simple Opencv program in C that creates a file capture from a .avi, and it plays it in a window highlighting faces. I'm running a self-compiled version of Opencv (i already tried the same with a jpeg image and it works).
Building goes well, no errors, no warning, but when i launch it this the console output this:
Unknown parameter encountered: "server role"
Ignoring unknown parameter "server role"
And the program simply stops
Previously it was complaining for a missing /home/#user/.smb/smb.conf file, so i tried installing samba ( even though i've still no idea what does samba have to do in all this )
here is my code:
main(){
printf("Ciao!");
cvNamedWindow("window", CV_WINDOW_AUTOSIZE);
cvWaitKey(0);
printf("ok");
CvCapture* capture = cvCreateFileCapture("monsters.avi");
CvHaarClassifierCascade* cascade = load_object_detector("haarcascade_frontalface_alt.xml");
CvMemStorage* storage = cvCreateMemStorage(0);
//List of the faces
CvSeq* faces;
while (0<10) {
CvArr* image = cvQueryFrame(capture);
double scale = 1;
faces = cvHaarDetectObjects(image,cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(1,1), cvSize(300,300));
int i;
for(i = 0; i < faces->total; i++ )
{
CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i );
cvRectangle( image,
cvPoint(face_rect.x*scale,face_rect.y*scale),
cvPoint((face_rect.x+face_rect.width)*scale,(face_rect.y+face_rect.height)*scale),
CV_RGB(255,0,0) , 3, 8, 0);
}
cvReleaseMemStorage( &storage );
cvShowImage("window", image);
}
cvWaitKey(0);
printf("Ciao!");
}
I thank you for your answer, i switched to C++ for my trials. Now i did this:
int main(){
namedWindow("Video", CV_WINDOW_FREERATIO);
VideoCapture cap("sintel.mp4");
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;
for(;;){
Mat frame;
cap>>frame;
cvtColor(frame, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
imshow("Video", edges);
//cvWaitKey(0);
}
return(0);
}
Now it succesfully load the video and query a frame, evry time i press a key it obviously query another frame and everything works fine, but if i comment the waitkey() the program simply hangs for a bit and crashes if i try to close the window, i'm starting to think there is a problem with codecs or something like that...
There are so many potential problems in the code, most of them related to not coding defensively.
What is cvWaitKey(0); doing after cvNamedWindow()? It's unecessary, remove it!
What happens if the capture was unsucessful? Code defensively:
CvCapture* capture = cvCreateFileCapture("monsters.avi");
if (!capture)
{
// File not found, handle error and possibly quit the application
}
and you should use this technique for every pointer that you receive from OpenCV, ok?
One of the major problems, is that you allocate memory for CvMemStorage before the loop, but inside the loop you release it, which means that after the first loop iteration there will be no longer a valid CvMemStorage* storage, and that's a HUGE problem.
Either move the allocation procedure to the beginning of the loop, so on every iteration memory is allocated/deallocated, or move the cvReleaseMemStorage( &storage ); call out of the loop.
Now it works fine, i changed cvWaitKey() with this
if(waitKey(30) >= 0) break;
I don't understand exactly why but now everything works as it should :)

How do I access functions from libsndfile-1.dll in MSVC?

I'm having trouble getting libsndfile-1.dll to work in my MSVC project. I can load the library and retrieve the version string from the dll by calling sf_command() from my code. However, I can't seem to get sf__open() to return a SNDFILE pointer.
I've also noticed that I can't get fopen() to return a FILE pointer either (maybe this is related, I think sf_open() uses fopen()!?).
I'm pretty new to MSVC, C/C++ and windows in general so I'm probably missing something really obvious.
My main.cpp looks like this:
#include <windows.h>
#include <stdio.h>
#include "sndfile.hh"
// create some function pointers to point to the dll function addresses
// I'm winging this a bit. hopefully it's right!? seems to work!
typedef int (*SF_COMMAND)(SNDFILE*, int, void*, int);
typedef SNDFILE* (*SF_OPEN)(const char*, int, SF_INFO*);
int main()
{
// dll handle
HINSTANCE hDLL = NULL;
// create some vars to store the dll funcs in
SF_COMMAND sf_command;
SF_OPEN sf_open;
// load the dll
hDLL = LoadLibrary(L"libsndfile-1.dll");
// check the dll loaded
if( NULL == hDLL )
{
printf("Error, Could not load library \n");
return 1;
}
// get the dll funcs
sf_command = (SF_COMMAND)GetProcAddress(hDLL, "sf_command");
sf_open = (SF_OPEN)GetProcAddress(hDLL, "sf_open");
// check we got the funcs
if(!(sf_command && sf_open)){
printf("Error exporting dll functions \n");
return 2;
}
// all good so far!
// try the first function
char* version_string[sizeof(char*)*4];
int res = sf_command(NULL, SFC_GET_LIB_VERSION, &version_string, sizeof(version_string));
if(res){
// all good!
printf("Version: %s \n", version_string);
}
// now try and create a SNDFILE pointer
SF_INFO info;
SNDFILE* sfp = sf_open("c:\\Godspeed.aif", SFM_READ, &info);
if(sfp){
printf("Hurray! successfully opened the SNDFILE!! \n");
}else{
printf("Doh! couldn't open the SNDFILE!! \n");
// Grr!!
return 3;
}
return 0;
}
The project builds and exits with code 3 (couldn't open the file! (I'm pretty sure the file is there!!)).
When I run the exe the output is:
Version: libsndfile-1.0.17
Doh! couldn't open the SNDFILE
Does anyone have any suggestions as to where I'm going wrong?
Many thanks,
Josh.
Hmm, I really should learn not to post to forums late at night!
I had another attempt this morning and had the file open within minutes.
I was getting my paths all wrong (not used to these weird windows paths)!
I tried using a relative path and bingo!
Hope that helps someone!

What is a lightweight cross platform WAV playing library?

I'm looking for a lightweight way to make my program (written in C) be able to play audio files on either windows or linux. I am currently using windows native calls, which is essentially just a single call that is passed a filename. I would like something similar that works on linux.
The audio files are Microsoft PCM, Single channel, 22Khz
Any Suggestions?
Since I'm also looking for an answer for question I did a bit of research, and I haven't find any simple (simple like calling one function) way to play an audio file. But with some lines of code, it is possible even in a portable way using the already mentioned portaudio and libsndfile (LGPL).
Here is a small test case I've written to test both libs:
#include <portaudio.h>
#include <sndfile.h>
static int
output_cb(const void * input, void * output, unsigned long frames_per_buffer,
const PaStreamCallbackTimeInfo *time_info,
PaStreamCallbackFlags flags, void * data)
{
SNDFILE * file = data;
/* this should not actually be done inside of the stream callback
* but in an own working thread
*
* Note although I haven't tested it for stereo I think you have
* to multiply frames_per_buffer with the channel count i.e. 2 for
* stereo */
sf_read_short(file, output, frames_per_buffer);
return paContinue;
}
static void
end_cb(void * data)
{
printf("end!\n");
}
#define error_check(err) \
do {\
if (err) { \
fprintf(stderr, "line %d ", __LINE__); \
fprintf(stderr, "error number: %d\n", err); \
fprintf(stderr, "\n\t%s\n\n", Pa_GetErrorText(err)); \
return err; \
} \
} while (0)
int
main(int argc, char ** argv)
{
PaStreamParameters out_param;
PaStream * stream;
PaError err;
SNDFILE * file;
SF_INFO sfinfo;
if (argc < 2)
{
fprintf(stderr, "Usage %s \n", argv[0]);
return 1;
}
file = sf_open(argv[1], SFM_READ, &sfinfo);
printf("%d frames %d samplerate %d channels\n", (int)sfinfo.frames,
sfinfo.samplerate, sfinfo.channels);
/* init portaudio */
err = Pa_Initialize();
error_check(err);
/* we are using the default device */
out_param.device = Pa_GetDefaultOutputDevice();
if (out_param.device == paNoDevice)
{
fprintf(stderr, "Haven't found an audio device!\n");
return -1;
}
/* stero or mono */
out_param.channelCount = sfinfo.channels;
out_param.sampleFormat = paInt16;
out_param.suggestedLatency = Pa_GetDeviceInfo(out_param.device)->defaultLowOutputLatency;
out_param.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(&stream, NULL, &out_param, sfinfo.samplerate,
paFramesPerBufferUnspecified, paClipOff,
output_cb, file);
error_check(err);
err = Pa_SetStreamFinishedCallback(stream, &end_cb);
error_check(err);
err = Pa_StartStream(stream);
error_check(err);
printf("Play for 5 seconds.\n");
Pa_Sleep(5000);
err = Pa_StopStream(stream);
error_check(err);
err = Pa_CloseStream(stream);
error_check(err);
sf_close(file);
Pa_Terminate();
return 0;
}
Some notes to the example. It is not good practice to do the data loading inside of the stream callback, but inside an own loading thread. If you need to play several audio files it becomes even more difficult, because not all portaudio backends support multiple streams for one device, for example the OSS backend doesn't, but the ALSA backend does. I don't know how the situation is on windows. Since all your input files are of the same type you could mix them on you own, which complicates the code a bit more, but then you'd have also support for OSS. If you would have also different sample rates or number of channels, it'd become very difficult.
So If you don't want to play multiple files at the same time, this could be a solution or at least a start for you.
SDL_Mixer, although not very lightweight, does have a simple interface to play WAV files. I believe, like SDL, SDL_Mixer is also LGPL.
OpenAL is another cross platform audio library that is more geared towards 3D audio.
Yet another open source audio library that you might want to check it out is PortAudio
I've used OpenAL to play wav files as alerts/warnings in an Air Traffic Control system
The advantages I've found are
it is cross platform
works with C (and others but your question is about C)
light weight
good documentation available on the web
the license is LGPL so you call the API with no license problems
You can try with this one: libao
I like FMOD. The license is free for personal use, and very reasonable for small shareware or commercial projects
You could also try Audiere. The last release is dated 2006, but it is open-source and licensed under the LGPL.
I used irrKlang !
"irrKlang is a cross platform sound library for C++, C# and all .NET languages"
http://www.ambiera.com/irrklang/

Resources