Hi all.. I have a bizarre bug I am trying to work out:
Click here to download full source
Hi all who could help me with this:
I was trying to create a very small library that could play Ogg Vorbis files cross platform.
To do this, I combined the Integer-only C "tremor" ogg decoder library that works exactly like
libvorbisfile, and the PortAudio output library. This combination is implemented in a small
little file called Portogg.c in the 'src' directory.
This compiles and links fine, but on my setup (mingw/w32 on msys),
there was a bizarre segmentation fault in the final executable.
To run some tests, I reproduced the same code from my test program (main.c) on a lower level by including it all
in one file, test_w_saw.c . Weirdly enough, the code runs as intended in test.exe, but not in main.exe.
Several runs in debug mode and with gdb have been unhelpful. I realize that this isn't quite NeHe topic, but I like this forum and the people in it. Does anyone out there think they can help?
portogg.h
/*standard c header file crap goes here*/
struct port_ogg_sound_s
{
unsigned char* codedbufferbegin;
unsigned short codedbufferlength;
unsigned long numsamplestotal;
unsigned long rate;
unsigned char channels;
short currvolume;
PABLIO_Stream *pa_stream;
OggVorbis_File *ovs_file;
char is_playing;
};
/*some functions with prefix port_ogg_*/
portogg.c
/* portogg.c, the source file for portogg, a glue library to play ogg vorbis sounds
Copyright (C) 2005 Steve*******
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Original Creation DATE: 7/20/05
*/
#include "./portogg.h"
short globalvolume = 32767;
#define MAX_BUFFER 128
char buffer[MAX_BUFFER];
int port_ogg_load_sound(port_ogg_sound* out_sound,char* filename)
{
PaError err;
PABLIO_Stream *aOutStream;
OggVorbis_File *vf=(OggVorbis_File *)malloc(sizeof(OggVorbis_File));
FILE *fi;
out_sound->ovs_file = vf;
out_sound->pa_stream = aOutStream;
fi = fopen(filename,"rb");
if(!fi)
{
return PO_E_FILE_NOT_FOUND;
}
if(ov_open(fi,vf,NULL,0) < 0)
{
/*error: stream is not an ogg*/
return PO_E_NOT_OGG;
}
ov_comment(vf,-1);
vorbis_info vfi;
vfi = *(ov_info(vf,-1));
out_sound->numsamplestotal=(unsigned long)ov_pcm_total(vf,-1);
ov_comment(vf,-1);
out_sound->channels = (unsigned char)vfi.channels;
out_sound->rate = vfi.rate;
err = OpenAudioStream( &aOutStream, vfi.rate, paInt16,
(PABLIO_WRITE | (vfi.channels >= 2 ? PABLIO_STEREO : PABLIO_MONO)) );
if( err != paNoError )
{
return err;
}
return -1;
}
/* loads a single ogg vorbis sound into the engine
Arg1: the address of a struct to recieve data
Arg2: the buffer of compressed data to be played
(a memory residing ogg file dump)
Arg3: the length of the buffer of compressed data
returns 0 if error, 1 if none.
*/
char port_ogg_is_playing(port_ogg_sound* sound)
{
return (char)sound->is_playing;
}
/* queries if the ogg vorbis sound is playing
Arg1: The sound to query
returns true if it is playing, false if it isn't playing
*/
int port_ogg_play_sound(port_ogg_sound* sound)
{
sound->is_playing=1;
return 1;
}
/* instructs the engine to play a sound
Arg1:` sound to play
Arg2: not required, defaults to false: A flag to play looping?
Arg3: not required, defaults to ???:Size of per-callback buffer
*/
int current_section=0;
int port_ogg_update_sound(port_ogg_sound* sound)
{
//if(sound->is_playing)
//{
int ret=ov_read(sound->ovs_file,buffer,MAX_BUFFER,¤t_section);
/* Write samples to output. */
WriteAudioStream( sound->pa_stream, buffer, MAX_BUFFER/(sizeof(short)*(sound->channels)) );
//}
return 0;
}
/*
Hands control back to the engine to process a particular sound (not truly multithreaded)
Arg1: sound to process
*/
int port_ogg_stop_sound(port_ogg_sound* sound)
{
sound->is_playing=0;
return 1;
}
/* Insturcts the engine to stop a sound after finishing the buffer
Arg1: Sound to stop
*/
int port_ogg_unload_sound(port_ogg_sound* sound)
{
PABLIO_Stream *aOutStream;
OggVorbis_File *vf;
vf = (OggVorbis_File *)sound->ovs_file;
aOutStream = (PABLIO_Stream *)sound->pa_stream;
CloseAudioStream( aOutStream );
ov_clear(vf);
return 0;
}
/* collect a sound from memory, stop playing it, and clean it up
Arg1: Sound to scrub out
*/
int port_ogg_global_volume(short v)
{
globalvolume = (short)((((long)v) * 36737) / 1000);
return 1;
}
/* Sets global volume for engine
Arg1: number from -1000 to 1000 for volume
*/
int port_ogg_sound_volume(port_ogg_sound* in_sound,short v)
{
in_sound->currvolume = (short)((((long)v) * 36737) / 1000);
return 1;
}
/* Sets sound volume for a particular stream
Arg1: Sound to control
Arg2: number from -1000 to 1000 for volume
*/
main.c
#include <stdio.h>
#include <stdlib.h>
#include "inc/portogg.h"
int main(int argc, char *argv[])
{
port_ogg_sound T;
printf("sound created\n");
port_ogg_load_sound(&T,"Fenster.ogg");
printf("sound loaded\n");
port_ogg_play_sound(&T);
printf("sound played\n");
int i=0;
while(1)
{
//printf("%i: Sound is playing\n",++i);
port_ogg_update_sound(&T);
}
port_ogg_stop_sound(&T);
printf("sound stopped");
port_ogg_unload_sound(&T);
system("PAUSE");
return 0;
}
test_w_saw.c
/*
* $Id: test_w_saw.c,v 1.1.1.1.4.1 2003/02/12 02:22:21 philburk Exp $
* test_w_saw.c
* Generate stereo sawtooth waveforms.
*
* Author: Phil Burk, http://www.softsynth.com
*
* This program uses PABLIO, the Portable Audio Blocking I/O Library.
* PABLIO is built on top of PortAudio, the Portable Audio Library.
*
* For more information see: http://www.audiomulch.com/portaudio/
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "src/portaudio/inc/pablio.h"
#include "src/tremor/inc/ivorbiscodec.h"
#include "src/tremor/inc/ivorbisfile.h"
#include <string.h>
#define SAMPLE_RATE (44100)
#define NUM_SECONDS (15)
#define SAMPLES_PER_FRAME (2)
#define FREQUENCY (220.0f)
#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE)
#define FRAMES_PER_BLOCK (100)
short samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
short phases[SAMPLES_PER_FRAME];
unsigned long ipow(int f)
{
return (1 << f);
}
char* data;
char* datacurs;
/*typedef struct {
size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
int (*close_func) (void *datasource);
long (*tell_func) (void *datasource);
} ov_callbacks;*/
/*******************************************************************/
int main(void)
{
int i,j;
PaError err;
PABLIO_Stream *aOutStream;
OggVorbis_File *vf=(OggVorbis_File *)malloc(sizeof(OggVorbis_File));
FILE *fi;
unsigned long BLOCKSIZE=0;
fi = fopen("Fenster.ogg","rb");
printf("file loaded\n");
int current_section;
if(ov_open(fi, vf, NULL, 0) < 0) {
fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
exit(1);
}
fprintf(stderr,"hi. Input buffersize power of 2\n");
char ss[5];
BLOCKSIZE = ipow(atoi(gets(ss)));
char *pcmout = malloc(BLOCKSIZE);
fprintf(stderr,"\nBuffer is %i bytes\n",BLOCKSIZE);
char **ptr=ov_comment(vf,-1)->user_comments;
vorbis_info *vi=ov_info(vf,-1);
while(*ptr){
fprintf(stderr,"%s\n",*ptr);
++ptr;
}
printf("Generate sawtooth waves using PABLIO.\n");
fflush(stdout);
fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
fprintf(stderr,"\nDecoded length: %ld samples\n",
(long)ov_pcm_total(vf,-1));
fprintf(stderr,"Encoded by: %s\n\n",ov_comment(vf,-1)->vendor);
/* Open simplified blocking I/O layer on top of PortAudio. */
err = OpenAudioStream( &aOutStream, vi->rate, paInt16,
(PABLIO_WRITE | (vi->channels >= 2 ? PABLIO_STEREO : PABLIO_MONO)) );
if( err != paNoError ) goto error;
/* Initialize oscillator phases. */
phases[0] = 0.0;
phases[1] = 0.0;
int status;
int c=0;
do
{
/* Generate sawtooth waveforms in a block for efficiency. */
status=ov_read(vf,pcmout,BLOCKSIZE,¤t_section);
fprintf(stderr,"b%i:playing\n",++c);
/* Write samples to output. */
WriteAudioStream( aOutStream, pcmout, BLOCKSIZE/(sizeof(short)*(vi->channels)) );
}while(status);
CloseAudioStream( aOutStream );
ov_clear(vf);
printf("Sawtooth sound test complete.\n" );
fflush(stdout);
free(pcmout);
return 0;
error:
fprintf( stderr, "An error occured while using PABLIO\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return -1;
}