123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242(*
* Copyright 2003-2011 Savonet team
*
* This file is part of Ocaml-flac.
*
* Ocaml-flac is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Ocaml-flac 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Ocaml-flac; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)(* Author; Romain Beauxis <toots@rastageeks.org> *)exceptionInternallet()=Callback.register_exception"flac_exn_internal"InternalmoduleDecoder=structtypet(** Possible states of a decoder. *)typestate=[`Search_for_metadata|`Read_metadata|`Search_for_frame_sync|`Read_frame|`End_of_stream|`Ogg_error|`Seek_error|`Aborted|`Memory_allocation_error|`Uninitialized]exceptionLost_syncexceptionBad_headerexceptionFrame_crc_mismatchexceptionUnparseable_streamexceptionNot_flaclet()=Callback.register_exception"flac_dec_exn_lost_sync"Lost_sync;Callback.register_exception"flac_dec_exn_bad_header"Bad_header;Callback.register_exception"flac_dec_exn_crc_mismatch"Frame_crc_mismatch;Callback.register_exception"flac_dec_exn_unparseable_stream"Unparseable_streamtypeinfo={sample_rate:int;channels:int;bits_per_sample:int;total_samples:int64;md5sum:string;}typecomments=string*(string*string)listtypecomments_array=string*stringarrayexternalinfo:t->info*comments_arrayoption="ocaml_flac_decoder_info"letsplit_commentcomment=tryletequal_pos=String.index_fromcomment0'='inletc1=String.uppercase_ascii(String.subcomment0equal_pos)inletc2=String.subcomment(equal_pos+1)(String.lengthcomment-equal_pos-1)in(c1,c2)withNot_found->(comment,"")let_commentscmts=matchcmtswith|None->None|Some(vd,cmts)->Some(vd,Array.to_list(Array.mapsplit_commentcmts))letinfox=tryletinfo,comments=infoxin(info,_commentscomments)withInternal->raiseNot_flacexternalalloc:seek:(int64->unit)option->tell:(unit->int64)option->length:(unit->int64)option->eof:(unit->bool)option->read:(bytes->int->int->int)->write:(floatarrayarray->unit)->unit->t="ocaml_flac_decoder_alloc_bytecode""ocaml_flac_decoder_alloc_native"externalcleanup:t->unit="ocaml_flac_cleanup_decoder"externalinit:t->unit="ocaml_flac_decoder_init"letcreate?seek?tell?length?eof~read~write()=letwritepcm=write(Array.copypcm)inletdec=alloc~seek~tell~length~eof~read~write()inGc.finalisecleanupdec;initdec;letinfo,comments=infodecin(dec,info,comments)externalstate:t->state="ocaml_flac_decoder_state"externalprocess:t->unit="ocaml_flac_decoder_process"externalseek:t->Int64.t->bool="ocaml_flac_decoder_seek"externalflush:t->bool="ocaml_flac_decoder_flush"externalreset:t->bool="ocaml_flac_decoder_reset"externalto_s16le:floatarrayarray->string="caml_flac_float_to_s16le"moduleFile=structtypehandle={fd:Unix.file_descr;dec:t;info:info;comments:(string*(string*string)list)option;}letcreate_from_fd~writefd=letread=Unix.readfdinletseekn=letn=Int64.to_intninignore(Unix.lseekfdnUnix.SEEK_SET)inlettell()=Int64.of_int(Unix.lseekfd0Unix.SEEK_CUR)inletlength()=letstats=Unix.fstatfdinInt64.of_intstats.Unix.st_sizeinleteof()=letstats=Unix.fstatfdinUnix.lseekfd0Unix.SEEK_CUR=stats.Unix.st_sizeinletdec,info,comments=create~seek~tell~length~eof~write~read()in{fd;comments;dec;info}letcreate~writefilename=letfd=Unix.openfilefilename[Unix.O_RDONLY]0o640intrycreate_from_fd~writefdwithe->Unix.closefd;raiseeendendmoduleEncoder=structtypeprivtypeparams={channels:int;bits_per_sample:int;sample_rate:int;compression_level:intoption;total_samples:int64option;}typecomments=(string*string)listtypet=priv*paramsexceptionInvalid_dataexceptionInvalid_metadatalet()=Callback.register_exception"flac_enc_exn_invalid_metadata"Invalid_metadataexternalvorbiscomment_entry_name_is_legal:string->bool="ocaml_flac_encoder_vorbiscomment_entry_name_is_legal"externalvorbiscomment_entry_value_is_legal:string->bool="ocaml_flac_encoder_vorbiscomment_entry_value_is_legal"externalalloc:(string*string)array->seek:(int64->unit)option->tell:(unit->int64)option->write:(bytes->int->unit)->params->priv="ocaml_flac_encoder_alloc"externalcleanup:priv->unit="ocaml_flac_cleanup_encoder"externalinit:priv->unit="ocaml_flac_encoder_init"letcreate?(comments=[])?seek?tell~writep=ifp.channels<=0thenraiseInvalid_data;letcomments=Array.of_listcommentsinletwriteblen=write(Bytes.subb0len)inletenc=alloccomments~seek~tell~writepinGc.finalisecleanupenc;initenc;(enc,p)externalprocess:priv->floatarrayarray->int->unit="ocaml_flac_encoder_process"letprocess(enc,p)data=ifArray.lengthdata<>p.channelsthenraiseInvalid_data;processencdatap.bits_per_sampleexternalfinish:priv->unit="ocaml_flac_encoder_finish"letfinish(enc,_)=finishencexternalfrom_s16le:string->int->floatarrayarray="caml_flac_s16le_to_float"moduleFile=structtypehandle={fd:Unix.file_descr;enc:t}letcreate_from_fd?commentsparamsfd=letwrites=letlen=Bytes.lengthsinletrecfpos=ifpos<lenthen(letret=Unix.writefdspos(len-pos)inf(pos+ret))inf0inletseekn=letn=Int64.to_intninignore(Unix.lseekfdnUnix.SEEK_SET)inlettell()=Int64.of_int(Unix.lseekfd0Unix.SEEK_CUR)inletenc=create?comments~seek~tell~writeparamsin{fd;enc}letcreate?commentsparamsfilename=letfd=Unix.openfilefilename[Unix.O_CREAT;Unix.O_RDWR]0o640increate_from_fd?commentsparamsfdendend