Opus to Wav working example

Signed-off-by: Mahyar Koshkouei <deltabeard@users.noreply.github.com>
This commit is contained in:
Mahyar Koshkouei
2016-12-08 23:43:27 +00:00
parent 78a874f2c0
commit 2805088a4a

View File

@@ -17,6 +17,7 @@
#if !defined(_POSIX_SOURCE) #if !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1 # define _POSIX_SOURCE 1
#endif #endif
#include <3ds.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
@@ -28,146 +29,118 @@
# define fileno _fileno # define fileno _fileno
#endif #endif
static void put_le32(unsigned char *_dst,opus_uint32 _x){ #define BUFFER_SIZE 120*48*2
_dst[0]=(unsigned char)(_x&0xFF);
_dst[1]=(unsigned char)(_x>>8&0xFF);
_dst[2]=(unsigned char)(_x>>16&0xFF);
_dst[3]=(unsigned char)(_x>>24&0xFF);
}
/*Make a header for a 48 kHz, stereo, signed, 16-bit little-endian PCM WAV.*/ int convOpus(const char* in, const char *outf)
static void make_wav_header(unsigned char _dst[44],ogg_int64_t _duration){ {
/*The chunk sizes are set to 0x7FFFFFFF by default.
Many, though not all, programs will interpret this to mean the duration is
"undefined", and continue to read from the file so long as there is actual
data.*/
static const unsigned char WAV_HEADER_TEMPLATE[44]={
'R','I','F','F',0xFF,0xFF,0xFF,0x7F,
'W','A','V','E','f','m','t',' ',
0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00,
0x04,0x00,0x10,0x00,'d','a','t','a',
0xFF,0xFF,0xFF,0x7F
};
memcpy(_dst,WAV_HEADER_TEMPLATE,sizeof(WAV_HEADER_TEMPLATE));
if(_duration>0){
if(_duration>0x1FFFFFF6){
fprintf(stderr,"WARNING: WAV output would be larger than 2 GB.\n");
fprintf(stderr,
"Writing non-standard WAV header with invalid chunk sizes.\n");
}
else{
opus_uint32 audio_size;
audio_size=(opus_uint32)(_duration*4);
put_le32(_dst+4,audio_size+36);
put_le32(_dst+40,audio_size);
}
}
}
int convOpus(const char* in, const char *outf){
OggOpusFile *of; OggOpusFile *of;
FILE *wav; FILE *wav;
ogg_int64_t duration; ogg_int64_t duration = 0;
unsigned char wav_header[44];
int ret; int ret;
int output_seekable; int output_seekable;
ogg_int64_t nsamples = 0;
opus_int16* pcm = malloc(BUFFER_SIZE*sizeof(opus_int16));
unsigned char* out = malloc(BUFFER_SIZE*2*sizeof(unsigned char));
of = op_open_file(in, &ret); of = op_open_file(in, &ret);
if((wav = fopen(outf, "w+")) == NULL) if((wav = fopen(outf, "w+")) == NULL)
{ {
fprintf(stderr,"Failed to open file '%s': %i\n",outf,errno); fprintf(stderr,"Failed to open file '%s': %i %s\n",outf,errno, strerror(errno));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(of==NULL){ if(of == NULL)
{
fprintf(stderr,"Failed to open file '%s': %i\n",in,ret); fprintf(stderr,"Failed to open file '%s': %i\n",in,ret);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
duration=0; output_seekable = fseek(wav, 0, SEEK_CUR);
output_seekable=fseek(wav,0,SEEK_CUR)!=-1;
if(op_seekable(of)){ if(op_seekable(of))
{
fprintf(stderr,"Total number of links: %i\n",op_link_count(of)); fprintf(stderr,"Total number of links: %i\n",op_link_count(of));
duration=op_pcm_total(of,-1); // Get PCM length of entire stream.
duration = op_pcm_total(of, -1);
fprintf(stderr,"Total duration: "); fprintf(stderr,"Total duration: ");
fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration); fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
} }
else if(!output_seekable){ else if(output_seekable < 0)
{
fprintf(stderr,"WARNING: Neither input nor output are seekable.\n"); fprintf(stderr,"WARNING: Neither input nor output are seekable.\n");
fprintf(stderr, fprintf(stderr,
"Writing non-standard WAV header with invalid chunk sizes.\n"); "Writing non-standard WAV header with invalid chunk sizes.\n");
} }
make_wav_header(wav_header,duration); for(;;)
{
int si;
if(!fwrite(wav_header,sizeof(wav_header),1,wav)){ /*Although we would generally prefer to use the float interface, WAV
fprintf(stderr,"Error writing WAV header: %s\n",strerror(errno)); files with signed, 16-bit little-endian samples are far more
ret=EXIT_FAILURE; universally supported, so that's what we output.*/
} ret = op_read_stereo(of, pcm, sizeof(pcm)/sizeof(*pcm));
else{
ogg_int64_t nsamples;
opus_int16* pcm = malloc(120*48*2*sizeof(opus_int16));
unsigned char* out = malloc(120*48*2*2*sizeof(unsigned char));
nsamples=0;
for(;;){
int si;
/*Although we would generally prefer to use the float interface, WAV
files with signed, 16-bit little-endian samples are far more
universally supported, so that's what we output.*/
ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm));
if(ret<0){
fprintf(stderr,"\nError decoding '%s': %i\n",in,ret);
ret=EXIT_FAILURE;
break;
}
if(ret<=0){
ret=EXIT_SUCCESS;
break;
}
/*Ensure the data is little-endian before writing it out.*/
for(si=0;si<2*ret;si++){
out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
}
if(!fwrite(out,sizeof(*out)*4*ret,1,wav)){
fprintf(stderr,"\nError writing decoded audio data: %s\n",
strerror(errno));
ret=EXIT_FAILURE;
break;
}
nsamples+=ret;
if(nsamples % 1000 == 0) if(ret < 0)
fprintf(stderr, "\rSample: %li", (long)nsamples); {
//End of for loop. fprintf(stderr, "\nError decoding '%s': %i\n", in, ret);
ret = EXIT_FAILURE;
break;
} }
free(pcm);
free(out); if(ret == 0)
if(ret==EXIT_SUCCESS){ {
fprintf(stderr,"\nDone: played "); ret = EXIT_SUCCESS;
fprintf(stderr," (%li samples @ 48 kHz).\n",(long)nsamples); break;
} }
if(op_seekable(of)&&nsamples!=duration){
fprintf(stderr,"\nWARNING: " /*Ensure the data is little-endian before writing it out.*/
"Number of output samples does not match declared file duration.\n"); for(si=0; si<2*ret; si++)
if(!output_seekable)fprintf(stderr,"Output WAV file will be corrupt.\n"); {
out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
} }
if(output_seekable&&nsamples!=duration){
make_wav_header(wav_header,nsamples); if(fwrite(out, sizeof(u32), 1, wav) == 0)
if(fseek(wav,0,SEEK_SET)|| {
!fwrite(wav_header,sizeof(wav_header),1,wav)){ fprintf(stderr, "\nError writing decoded audio data: %s\n",
fprintf(stderr,"Error rewriting WAV header: %s\n",strerror(errno)); strerror(errno));
ret=EXIT_FAILURE; ret = EXIT_FAILURE;
} break;
} }
nsamples += ret;
if(nsamples % 1000 == 0)
fprintf(stderr, "\rRet: %d, Sample: %li", ret, (long)nsamples);
} }
fclose(wav); gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();
free(pcm);
free(out);
if(ret == EXIT_SUCCESS)
{
fprintf(stderr, "\nDone: played ");
fprintf(stderr, " (%li samples @ 48 kHz).\n", (long)nsamples);
}
if(op_seekable(of) && nsamples != duration)
{
fprintf(stderr, "\nWARNING: Number of output samples does not match "
"declared file duration.\n");
if(output_seekable < 0)
fprintf(stderr, "Output WAV file will be corrupt.\n");
}
if(fclose(wav) != 0)
fprintf(stderr, "\nError closing file: %d - %s\n", errno, strerror(errno));
op_free(of); op_free(of);
return ret; return ret;
} }