openalbridge/loaders.c
changeset 2191 20c62f787a4d
child 2200 8192be6e3aef
equal deleted inserted replaced
2190:cfcad6142d48 2191:20c62f787a4d
       
     1 /*
       
     2  * OpenAL Bridge - a simple portable library for OpenAL interface
       
     3  * Copyright (c) 2009 Vittorio Giovara <vittorio.giovara@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  */
       
    18 
       
    19 #include <stdio.h>
       
    20 #include <stdlib.h>
       
    21 #include <stdint.h>
       
    22 #include "al.h"
       
    23 #include "alc.h"
       
    24 #include "loaders.h"
       
    25 #include "endianness.h"
       
    26 #include "wrappers.h"
       
    27 
       
    28 #ifdef __CPLUSPLUS
       
    29 extern "C" {
       
    30 #endif 
       
    31 	
       
    32 	extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
       
    33 	extern long ov_read(OggVorbis_File *vf,char *buffer,int length,int bigendianp,int word,int sgned,int *bitstream);
       
    34 	extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
       
    35 	extern long ov_read(OggVorbis_File *vf,char *buffer,int length,int bigendianp,int word,int sgned,int *bitstream);
       
    36 	extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
       
    37 	extern vorbis_comment *ov_comment(OggVorbis_File *f, int num);
       
    38 	
       
    39 	int load_WavPcm (const char *filename, ALenum *format, uint8_t** data, ALsizei *bitsize, ALsizei *freq) {
       
    40 		WAV_header_t WAVHeader;
       
    41 		FILE *wavfile;
       
    42 		int t, n = 0;
       
    43 		
       
    44 		wavfile = Fopen(filename, "rb");
       
    45 		
       
    46 		fread(&WAVHeader.ChunkID, sizeof(uint32_t), 1, wavfile);
       
    47 		fread(&WAVHeader.ChunkSize, sizeof(uint32_t), 1, wavfile);
       
    48 		fread(&WAVHeader.Format, sizeof(uint32_t), 1, wavfile);
       
    49 		
       
    50 #ifdef DEBUG
       
    51 		fprintf(stderr, "ChunkID: %X\n", invert_endianness(WAVHeader.ChunkID));
       
    52 		fprintf(stderr, "ChunkSize: %d\n", WAVHeader.ChunkSize);
       
    53 		fprintf(stderr, "Format: %X\n", invert_endianness(WAVHeader.Format));
       
    54 #endif
       
    55 		
       
    56 		fread(&WAVHeader.Subchunk1ID, sizeof(uint32_t), 1, wavfile);
       
    57 		fread(&WAVHeader.Subchunk1Size, sizeof(uint32_t), 1, wavfile);
       
    58 		fread(&WAVHeader.AudioFormat, sizeof(uint16_t), 1, wavfile);
       
    59 		fread(&WAVHeader.NumChannels, sizeof(uint16_t), 1, wavfile);
       
    60 		fread(&WAVHeader.SampleRate, sizeof(uint32_t), 1, wavfile);
       
    61 		fread(&WAVHeader.ByteRate, sizeof(uint32_t), 1, wavfile);
       
    62 		fread(&WAVHeader.BlockAlign, sizeof(uint16_t), 1, wavfile);
       
    63 		fread(&WAVHeader.BitsPerSample, sizeof(uint16_t), 1, wavfile);
       
    64 		
       
    65 #ifdef DEBUG
       
    66 		fprintf(stderr, "Subchunk1ID: %X\n", invert_endianness(WAVHeader.Subchunk1ID));
       
    67 		fprintf(stderr, "Subchunk1Size: %d\n", WAVHeader.Subchunk1Size);
       
    68 		fprintf(stderr, "AudioFormat: %d\n", WAVHeader.AudioFormat);
       
    69 		fprintf(stderr, "NumChannels: %d\n", WAVHeader.NumChannels);
       
    70 		fprintf(stderr, "SampleRate: %d\n", WAVHeader.SampleRate);
       
    71 		fprintf(stderr, "ByteRate: %d\n", WAVHeader.ByteRate);
       
    72 		fprintf(stderr, "BlockAlign: %d\n", WAVHeader.BlockAlign);
       
    73 		fprintf(stderr, "BitsPerSample: %d\n", WAVHeader.BitsPerSample);
       
    74 #endif
       
    75 		
       
    76 		do { //remove useless header chunks (plenty room for improvements)
       
    77 			t = fread(&WAVHeader.Subchunk2ID, sizeof(uint32_t), 1, wavfile);
       
    78 			if (invert_endianness(WAVHeader.Subchunk2ID) == 0x64617461)
       
    79 				break;
       
    80 			if (t <= 0) { //eof found
       
    81 				fprintf(stderr, "ERROR: wrong WAV header\n");
       
    82 				return AL_FALSE;
       
    83 			}
       
    84 		} while (1);
       
    85 		fread(&WAVHeader.Subchunk2Size, sizeof(uint32_t), 1, wavfile);
       
    86 		
       
    87 #ifdef DEBUG
       
    88 		fprintf(stderr, "Subchunk2ID: %X\n", invert_endianness(WAVHeader.Subchunk2ID));
       
    89 		fprintf(stderr, "Subchunk2Size: %d\n", WAVHeader.Subchunk2Size);
       
    90 #endif
       
    91 		
       
    92 		*data = (uint8_t*) malloc (sizeof(uint8_t) * WAVHeader.Subchunk2Size);
       
    93 		
       
    94 		//this could be improved
       
    95 		do {
       
    96 			n += fread(&((*data)[n]), sizeof(uint8_t), 1, wavfile);
       
    97 		} while (n < WAVHeader.Subchunk2Size);
       
    98 		
       
    99 		fclose(wavfile);	
       
   100 		
       
   101 #ifdef DEBUG
       
   102 		fprintf(stderr, "Last two bytes of data: %X%X\n", (*data)[n-2], (*data)[n-1]);
       
   103 #endif
       
   104 		
       
   105 		/*remaining parameters*/
       
   106 		//Valid formats are AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, and AL_FORMAT_STEREO16. 
       
   107 		if (WAVHeader.NumChannels == 1) {
       
   108 			if (WAVHeader.BitsPerSample == 8)
       
   109 				*format = AL_FORMAT_MONO8;
       
   110 			else {
       
   111 				if (WAVHeader.BitsPerSample == 16)
       
   112 					*format = AL_FORMAT_MONO16;
       
   113 				else {
       
   114 					fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n");
       
   115 					return AL_FALSE;
       
   116 				}
       
   117 			} 
       
   118 		} else {
       
   119 			if (WAVHeader.NumChannels == 2) {
       
   120 				if (WAVHeader.BitsPerSample == 8)
       
   121 					*format = AL_FORMAT_STEREO8;
       
   122 				else {
       
   123 					if (WAVHeader.BitsPerSample == 16)
       
   124 						*format = AL_FORMAT_STEREO16;
       
   125 					else {
       
   126 						fprintf(stderr, "ERROR: wrong WAV header - bitsample value\n");
       
   127 						return AL_FALSE;
       
   128 					}				
       
   129 				}
       
   130 			} else {
       
   131 				fprintf(stderr, "ERROR: wrong WAV header - format value\n");
       
   132 				return AL_FALSE;
       
   133 			}
       
   134 		}
       
   135 		
       
   136 		*bitsize = WAVHeader.Subchunk2Size;
       
   137 		*freq = WAVHeader.SampleRate;
       
   138 		return AL_TRUE;
       
   139 	}
       
   140 	
       
   141 	int load_OggVorbis (const char *filename, ALenum *format, uint8_t**data, ALsizei *bitsize, ALsizei *freq) {
       
   142 		//implementation inspired from http://www.devmaster.net/forums/showthread.php?t=1153
       
   143 		FILE			*oggFile;		// ogg handle
       
   144 		OggVorbis_File  oggStream;		// stream handle
       
   145 		vorbis_info		*vorbisInfo;	// some formatting data
       
   146 		vorbis_comment	*vorbisComment;	// other less useful data
       
   147 		int64_t			pcm_length;		// length of the decoded data
       
   148 		int size = 0;
       
   149 		int section, result, i;
       
   150 		
       
   151 		oggFile = Fopen(filename, "rb");
       
   152 		result = ov_open(oggFile, &oggStream, NULL, 0);
       
   153 		//TODO: check returning value of result
       
   154 		
       
   155 		vorbisInfo = ov_info(&oggStream, -1);
       
   156 		pcm_length = ov_pcm_total(&oggStream,-1) << vorbisInfo->channels;	
       
   157 		
       
   158 #ifdef DEBUG
       
   159 		vorbisComment = ov_comment(&oggStream, -1);
       
   160 		fprintf(stderr, "Version: %d\n", vorbisInfo->version);
       
   161 		fprintf(stderr, "Channels: %d\n", vorbisInfo->channels);
       
   162 		fprintf(stderr, "Rate (Hz): %d\n", vorbisInfo->rate);
       
   163 		fprintf(stderr, "Bitrate Upper: %d\n", vorbisInfo->bitrate_upper);
       
   164 		fprintf(stderr, "Bitrate Nominal: %d\n", vorbisInfo->bitrate_nominal);
       
   165 		fprintf(stderr, "Bitrate Lower: %d\n", vorbisInfo->bitrate_lower);
       
   166 		fprintf(stderr, "Bitrate Windows: %d\n", vorbisInfo->bitrate_window);
       
   167 		fprintf(stderr, "Vendor: %s\n", vorbisComment->vendor);
       
   168 		fprintf(stderr, "PCM data size: %d\n", pcm_length);
       
   169 		fprintf(stderr, "# comment: %d\n", vorbisComment->comments);
       
   170 		for (i = 0; i < vorbisComment->comments; i++)
       
   171 			fprintf(stderr, "\tComment %d: %s\n", i, vorbisComment->user_comments[i]);
       
   172 #endif
       
   173 		
       
   174 		//allocates enough room for the decoded data
       
   175 		*data = (uint8_t*) malloc (sizeof(uint8_t) * pcm_length);
       
   176 		
       
   177 		//there *should* not be ogg at 8 bits
       
   178 		if (vorbisInfo->channels == 1)
       
   179 			*format = AL_FORMAT_MONO16;
       
   180 		else {
       
   181 			if (vorbisInfo->channels == 2)
       
   182 				*format = AL_FORMAT_STEREO16;
       
   183 			else {
       
   184 				fprintf(stderr, "ERROR: wrong OGG header - channel value (%d)\n", vorbisInfo->channels);
       
   185 				return AL_FALSE;
       
   186 			}
       
   187 		}
       
   188 		
       
   189 		while(size < pcm_length)	{
       
   190 			//ov_read decodes the ogg stream and storse the pcm in data 
       
   191 			result = ov_read (&oggStream, *data + size, pcm_length - size, 0, 2, 1, &section);
       
   192 			if(result > 0) {
       
   193 				size += result;
       
   194 			} else {
       
   195 				if (result == 0)
       
   196 					break;
       
   197 				else { 
       
   198 					fprintf(stderr, "ERROR: end of file from OGG stream\n");
       
   199 					return AL_FALSE;
       
   200 				}
       
   201 			}
       
   202 		}
       
   203 		
       
   204 		//records the last fields
       
   205 		*bitsize = size;
       
   206 		*freq = vorbisInfo->rate;
       
   207 		return AL_TRUE;
       
   208 	}
       
   209 	
       
   210 #ifdef __CPLUSPLUS
       
   211 }
       
   212 #endif