woollybah 9 лет назад
Сommit
c7cf86d163
4 измененных файлов с 294 добавлено и 0 удалено
  1. 1 0
      .gitignore
  2. 12 0
      oggsaver.mod/doc/saveogg.bmx
  3. 122 0
      oggsaver.mod/oggencoder.c
  4. 159 0
      oggsaver.mod/oggsaver.bmx

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.bmx

+ 12 - 0
oggsaver.mod/doc/saveogg.bmx

@@ -0,0 +1,12 @@
+' saveogg.bmx
+
+Import axe.oggsaver
+
+Local sample:TAudioSample=CreateAudioSample( 11025,11025,SF_MONO16LE )
+
+For Local k=0 Until 11025
+        sample.samples[k]=Sin(k*360/32)*32767
+Next
+
+SaveOGG(sample,"sinwave.ogg")
+

+ 122 - 0
oggsaver.mod/oggencoder.c

@@ -0,0 +1,122 @@
+//oggencoder.c
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <time.h>
+#include <math.h>
+
+#include <vorbis/vorbisenc.h>
+//#include <vorbisenc.h>
+
+#define READ 1024
+
+typedef struct oggwriter oggwriter;
+
+struct oggwriter{
+	ogg_stream_state os; //take physical pages, weld into a logical stream of packets 
+	ogg_page         og; //one Ogg bitstream page.  Vorbis packets are inside 
+	ogg_packet       op; //one raw packet of data for decode 
+	
+	vorbis_info      vi; //struct that stores all the static vorbis bitstream settings 
+	vorbis_comment   vc; //struct that stores all the user comments 
+	
+	vorbis_dsp_state vd; //central working state for the packet->PCM decoder 
+	vorbis_block     vb; //local working space for packet->PCM decode 
+};
+
+int Encode_Ogg(void *stream,void(*writefunc)(void *bytes,int count,void *stream),int freq,int channels,float *samples,int length,float compression){
+
+	oggwriter *ogg;	
+	int eos;
+	int result;
+
+	ogg=(oggwriter*)malloc(sizeof(oggwriter));
+
+	vorbis_info_init(&ogg->vi);
+	
+	result=vorbis_encode_init_vbr(&ogg->vi,channels,freq,compression);	
+
+	if(result) return -1;	//error format not supported...
+
+// add a comment 
+
+	vorbis_comment_init(&ogg->vc);
+	vorbis_comment_add_tag(&ogg->vc,"ENCODER","encoder_example.c");
+	
+// set up the analysis state and auxiliary encoding storage 
+
+	vorbis_analysis_init(&ogg->vd,&ogg->vi);
+
+	vorbis_block_init(&ogg->vd,&ogg->vb);
+	
+	srand(time(NULL));
+	ogg_stream_init(&ogg->os,rand());
+		
+	ogg_packet header;
+	ogg_packet header_comm;
+	ogg_packet header_code;
+	
+	vorbis_analysis_headerout(&ogg->vd,&ogg->vc,&header,&header_comm,&header_code);
+	ogg_stream_packetin(&ogg->os,&header); //automatically placed in its own page 
+	ogg_stream_packetin(&ogg->os,&header_comm);
+	ogg_stream_packetin(&ogg->os,&header_code);
+
+//This ensures the actual audio data will start on a new page, as per spec
+	while(1){
+		result=ogg_stream_flush(&ogg->os,&ogg->og);
+		if(result==0)break;
+		writefunc(ogg->og.header,ogg->og.header_len,stream);
+		writefunc(ogg->og.body,ogg->og.body_len,stream);
+	}
+
+	int i,c,n;
+	eos=0;
+	
+	while(!eos){
+		if (length>0){
+			float **buffer=vorbis_analysis_buffer(&ogg->vd,READ);
+			n=length;if (n>READ) n=READ;			
+//uninterleave samples
+			for (i=0;i<n;i++){
+				for (c=0;c<channels;c++){
+					buffer[c][i]=*samples++;
+				}
+			}	
+			length=length-n;
+//tell the library how much we actually submitted
+			vorbis_analysis_wrote(&ogg->vd,i);
+		}else{
+			vorbis_analysis_wrote(&ogg->vd,0);
+		}
+		while(vorbis_analysis_blockout(&ogg->vd,&ogg->vb)==1){
+//analysis, assume we want to use bitrate management
+			vorbis_analysis(&ogg->vb,NULL);
+			vorbis_bitrate_addblock(&ogg->vb);		
+			while(vorbis_bitrate_flushpacket(&ogg->vd,&ogg->op)){
+//weld the packet into the bitstream
+				ogg_stream_packetin(&ogg->os,&ogg->op);
+//write out pages (if any)
+				while(!eos){
+					result=ogg_stream_pageout(&ogg->os,&ogg->og);
+					if(result==0)break;					
+					writefunc(ogg->og.header,ogg->og.header_len,stream);
+					writefunc(ogg->og.body,ogg->og.body_len,stream);
+					if (ogg_page_eos(&ogg->og)) eos=1;
+				}
+			}
+		}
+	}		
+//clean up and exit.  vorbis_info_clear() must be called last 
+	ogg_stream_clear(&ogg->os);
+	vorbis_block_clear(&ogg->vb);
+	vorbis_dsp_clear(&ogg->vd);
+	vorbis_comment_clear(&ogg->vc);
+	vorbis_info_clear(&ogg->vi);
+	
+	free(ogg);
+
+	return 0;	
+}

+ 159 - 0
oggsaver.mod/oggsaver.bmx

@@ -0,0 +1,159 @@
+
+Strict
+
+Rem
+bbdoc: OGG saver
+about:
+The axe.oggsaver module provides the ability to save OGG format #brl.audiosample.AudioSamples.
+End Rem
+Module axe.oggsaver
+
+ModuleInfo "Version: 1.01"
+ModuleInfo "Author: Simon Armstrong"
+ModuleInfo "License: Public Domain"
+ModuleInfo "Copyright: Blitz Research Ltd"
+ModuleInfo "Modserver: BRL"
+
+ModuleInfo "History: 1.01 Release"
+ModuleInfo "History: axe.saveogg module created due to growth restrictions on brl.oggloader"
+
+Import Pub.OggVorbis
+Import BRL.AudioSample
+
+Import "../../pub.mod/oggvorbis.mod/libogg-1.3.1/include/*.h"
+Import "../../pub.mod/oggvorbis.mod/libvorbis-1.3.4/include/*.h"
+Import "../../pub.mod/oggvorbis.mod/libvorbis-1.3.4/lib/*.h"
+Import "../../pub.mod/oggvorbis.mod/libvorbis-1.3.4/lib/vorbisenc.c"
+
+Import "oggencoder.c"
+
+Extern
+Function Encode_Ogg(outputstream:Object,callback:Byte Ptr,freq,channels,samples:Float Ptr,length,compression:Float)
+End Extern
+
+Private
+
+Function writefunc(bytes:Byte Ptr,count,stream:TStream) NODEBUG
+	stream.WriteBytes bytes,count
+End Function	
+
+Public
+
+Rem
+bbdoc: Save an Audio Sample in OGG format
+about:
+#SaveOGG saves @sample to @url in OGG format. If successful, #SaveOGG returns
+True, otherwise False.<br>
+<br>
+The optional @compression parameter should be in the range -0.1 to 1.0,
+where -0.1 indicates maximum compression and 1.0 indicates best quality.
+End Rem
+Function SaveOGG(sample:TAudioSample,URL:Object,compression#=0.1)
+	Local output:TStream
+	Local samples:Float[],channels,rate,count,i,res,w
+	Select sample.format
+		Case SF_MONO8
+			channels=1
+		Case SF_MONO16LE
+			channels=1			
+		Case SF_MONO16BE
+			channels=1
+		Case SF_STEREO8
+			channels=2
+		Case SF_STEREO16LE
+			channels=2
+		Case SF_STEREO16BE
+			channels=2
+	End Select
+	rate=sample.hertz
+	count=channels*sample.length
+	samples=New Float[count]
+	Local s:Byte Ptr=sample.samples
+	Select sample.format
+		Case SF_MONO8,SF_STEREO8
+			For i=0 Until count
+				samples[i]=(s[i]-127.5)/127.5
+			Next
+		Case SF_MONO16LE,SF_STEREO16LE
+			For i=0 Until count
+				w=(s[1] Shl 8)|(s[0])
+				If (w&$8000) w=w|$ffff0000	'sign extend
+				samples[i]=w/32768.0				
+				s=s+2
+			Next	
+		Case SF_MONO16BE,SF_STEREO16BE
+			For i=0 Until count
+				w=(s[0] Shl 8)|(s[1])
+				If (w&$8000) w=w|$ffff0000	'sign extend
+				samples[i]=w/32768.0				
+				s=s+2
+			Next	
+	End Select		
+	output=WriteStream(url)
+	If Not output Return -1
+	res=Encode_Ogg(output,writefunc,rate,channels,samples,sample.length,compression)
+	CloseStream(output)
+	Return res
+End Function
+
+
+
+Rem
+bbdoc: Save an Audio Sample in WAV format
+about:
+#SaveWAV saves @sample to @url in WAV format. If successful, #SaveWAV returns
+True, otherwise False.<br>
+End Rem
+Function SaveWAV(sample:TAudioSample,URL:Object)
+	Local output:TStream
+	Local channels
+	
+	Select sample.format
+		Case SF_MONO8
+			channels=1
+		Case SF_MONO16LE
+			channels=1			
+		Case SF_MONO16BE
+			channels=1
+		Case SF_STEREO8
+			channels=2
+		Case SF_STEREO16LE
+			channels=2
+		Case SF_STEREO16BE
+			channels=2
+	End Select
+
+	Local bitrate=8
+	
+	Local block = channels * bitrate / 8
+
+	Local count=block*sample.length
+
+
+	output=WriteStream(url)
+	If Not output Return -1
+	
+	'write wav header info
+	output.WriteString("RIFF")						'"RIFF" file description header (4 bytes)
+	output.WriteInt(count + 40)						'file size - 8 (4 bytes)
+	output.WriteString("WAVE")						'"WAVE" description header (4 bytes)
+	output.WriteString("fmt ")						'"fmt " description header (4 bytes)
+	output.WriteInt(16)								'size of WAVE section chunk (4 bytes)
+	output.WriteShort(1)							'WAVE type format (2 bytes)
+	output.WriteShort(channels)						'mono/stereo (2 bytes)
+	output.WriteInt(sample.hertz)					'sample rate (4 bytes)
+	output.WriteInt(sample.hertz * block)			'avg bytes/sec (4 bytes)
+	output.WriteShort(block)						'Block alignment (2 bytes)
+	output.WriteShort(bitrate)						'Bits/sample (2 bytes)
+	output.WriteString("data")						'"data" description header (4 bytes)
+	output.WriteInt(count)							'size of data chunk (4 bytes)
+	
+	For Local i=0 Until count
+		output.WriteByte sample.samples[i]
+	Next
+
+	CloseStream(output)
+	
+	Return True
+
+End Function