pax_global_header00006660000000000000000000000064141023237430014511gustar00rootroot0000000000000052 comment=0339d9d7d463f96d6d7e511c1b6ae85caed36009 ocaml-samplerate-0.1.6/000077500000000000000000000000001410232374300147435ustar00rootroot00000000000000ocaml-samplerate-0.1.6/.github/000077500000000000000000000000001410232374300163035ustar00rootroot00000000000000ocaml-samplerate-0.1.6/.github/workflows/000077500000000000000000000000001410232374300203405ustar00rootroot00000000000000ocaml-samplerate-0.1.6/.github/workflows/main.yml000066400000000000000000000006661410232374300220170ustar00rootroot00000000000000name: Build on: [push] jobs: build: runs-on: ${{ matrix.operating-system }} strategy: matrix: operating-system: [ubuntu-latest, macos-latest] ocaml-version: ['4.09.0'] steps: - uses: actions/checkout@v1 - uses: avsm/setup-ocaml@master with: ocaml-version: ${{ matrix.ocaml-version }} - run: opam pin add -n . - run: opam depext -yt samplerate - run: opam install -t . ocaml-samplerate-0.1.6/.gitignore000066400000000000000000000000631410232374300167320ustar00rootroot00000000000000*~ _build *.byte *.native _tests .merlin *.install ocaml-samplerate-0.1.6/.merlin000066400000000000000000000000211410232374300162230ustar00rootroot00000000000000S src/** B src/**ocaml-samplerate-0.1.6/.ocamlformat000066400000000000000000000003201410232374300172430ustar00rootroot00000000000000profile = conventional break-separators = after space-around-lists = false doc-comments = before match-indent = 2 match-indent-nested = always parens-ite exp-grouping = preserve module-item-spacing = compact ocaml-samplerate-0.1.6/CHANGES.md000066400000000000000000000017311410232374300163370ustar00rootroot000000000000000.1.6 (02-07-2021) ===== - Change licence to 2-clause BSD in order to match libsamplerate's licence (#1). - Fix various memory leaks due to incorrect handling of channels (#2). All offsets are sizes should now be in number of _frames_, i.e. number of samples _per channel_. 0.1.5 (14-11-2020) ===== - Switched to dune - Add `process_ba`. 0.1.4 (15-10-2016) ===== - Lift configure failure when compiling as root. 0.1.3 (03-08-2015) ===== - Dummy github release. 0.1.2 (18-20-2013) ===== - Cleanly handle case where input buffer has length 0. - Check for memory allocation errors. - Updated configure. 0.1.1 (12-10-2009) ===== - Added support for --enable-debugging configure option - Added NO_CUSTOM to build in standard mode. - Added prefix to main compilation variables if passed to configure. - Makefile now honnors LIBDIRS variable for linking against libraries located in other places than then standard ones. 0.1.0 (17/02/2009) ===== - Initial release ocaml-samplerate-0.1.6/COPYING000066400000000000000000000024661410232374300160060ustar00rootroot00000000000000Copyright (c) 2012-2016, Erik de Castro Lopo All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ocaml-samplerate-0.1.6/Makefile000066400000000000000000000001001410232374300163720ustar00rootroot00000000000000all: @dune build test: @dune runtest doc: @dune build @doc ocaml-samplerate-0.1.6/README.md000066400000000000000000000014541410232374300162260ustar00rootroot00000000000000ocaml-samplerate ================ This package contains an OCaml interface for the [samplerate library](http://libsndfile.github.io/libsamplerate/). Please read the COPYING file before using this software. Prerequisites ------------- - ocaml - libsamplerate - findlib - dune >= 2.0 Compilation ----------- ``` $ dune build ``` This should build both the native and the byte-code version of the extension library. Installation ------------ Via `opam`: ``` $ opam install samplerate ``` Via `dune` (for developers): ``` $ dune install ``` Bugs ---- Please report any issue in [the dedicated bugtracker](https://github.com/savonet/ocaml-samplerate/issues). Author ------ This author of this software may be contacted by electronic mail at the following address: savonet-users@lists.sourceforge.net. ocaml-samplerate-0.1.6/dune-project000066400000000000000000000011511410232374300172630ustar00rootroot00000000000000(lang dune 2.8) (version 0.1.6) (name samplerate) (source (github savonet/ocaml-samplerate)) (license BSD-2-Clause) (authors "The Savonet Team ") (maintainers "The Savonet Team ") (generate_opam_files true) (use_standard_c_and_cxx_flags false) (package (name samplerate) (synopsis "Samplerate audio conversion library") (description "Bindings for the samplerate library which provides functions for changing samplerate of audio data") (depends dune (dune-configurator :build) (conf-samplerate :build) (conf-pkg-config :build)) ) ocaml-samplerate-0.1.6/examples/000077500000000000000000000000001410232374300165615ustar00rootroot00000000000000ocaml-samplerate-0.1.6/examples/.gitignore000066400000000000000000000000051410232374300205440ustar00rootroot00000000000000test ocaml-samplerate-0.1.6/examples/dune000066400000000000000000000000541410232374300174360ustar00rootroot00000000000000(test (name test) (libraries samplerate)) ocaml-samplerate-0.1.6/examples/test.ml000066400000000000000000000015551410232374300201000ustar00rootroot00000000000000(* Test regular interface *) let () = let samples = 256 in let chans = 2 in let off = 11 in let buflen = (off + samples) * chans in let inbuf = Array.make buflen 0. in let outbuf = Array.make (buflen * 2) 0. in let conv = Samplerate.create Samplerate.Conv_linear chans in for _ = 1 to 10 do let i, o = Samplerate.process conv 2. inbuf off samples outbuf off (2 * samples) in Printf.printf "process: %d -> %d\n%!" i o done; print_newline () (* Test bigarray interface *) let () = let buflen = 1024 in let buf = Bigarray.Array1.create Bigarray.float32 Bigarray.c_layout buflen in let conv = Samplerate.create Samplerate.Conv_linear 1 in let outbuf = Bigarray.Array1.create Bigarray.float32 Bigarray.c_layout (2 * buflen) in let i, _ = Samplerate.process_ba conv 2. buf outbuf in Printf.printf "Converted %d out of %d.\n%!" i buflen ocaml-samplerate-0.1.6/samplerate.opam000066400000000000000000000016241410232374300177610ustar00rootroot00000000000000# This file is generated by dune, edit dune-project instead opam-version: "2.0" version: "0.1.6" synopsis: "Samplerate audio conversion library" description: "Bindings for the samplerate library which provides functions for changing samplerate of audio data" maintainer: ["The Savonet Team "] authors: ["The Savonet Team "] license: "BSD-2-Clause" homepage: "https://github.com/savonet/ocaml-samplerate" bug-reports: "https://github.com/savonet/ocaml-samplerate/issues" depends: [ "dune" {>= "2.8"} "dune-configurator" {build} "conf-samplerate" {build} "conf-pkg-config" {build} "odoc" {with-doc} ] build: [ ["dune" "subst"] {dev} [ "dune" "build" "-p" name "-j" jobs "@install" "@runtest" {with-test} "@doc" {with-doc} ] ] dev-repo: "git+https://github.com/savonet/ocaml-samplerate.git" ocaml-samplerate-0.1.6/src/000077500000000000000000000000001410232374300155325ustar00rootroot00000000000000ocaml-samplerate-0.1.6/src/config/000077500000000000000000000000001410232374300167775ustar00rootroot00000000000000ocaml-samplerate-0.1.6/src/config/discover.ml000066400000000000000000000012061410232374300211460ustar00rootroot00000000000000module C = Configurator.V1 let () = C.main ~name:"samplerate-pkg-config" (fun c -> let default : C.Pkg_config.package_conf = { libs = ["-lsamplerate"]; cflags = [] } in let conf = match C.Pkg_config.get c with | None -> default | Some pc -> ( match C.Pkg_config.query_expr_err pc ~package:"samplerate" ~expr:"samplerate" with | Error msg -> failwith msg | Ok deps -> deps ) in C.Flags.write_sexp "c_flags.sexp" conf.cflags; C.Flags.write_sexp "c_library_flags.sexp" conf.libs) ocaml-samplerate-0.1.6/src/config/dune000066400000000000000000000000751410232374300176570ustar00rootroot00000000000000(executable (name discover) (libraries dune.configurator)) ocaml-samplerate-0.1.6/src/dune000066400000000000000000000005531410232374300164130ustar00rootroot00000000000000(library (name samplerate) (public_name samplerate) (synopsis "OCaml bindings for samplerate") (libraries bigarray) (foreign_stubs (language c) (names samplerate_stubs) (flags (:include c_flags.sexp))) (c_library_flags (:include c_library_flags.sexp))) (rule (targets c_flags.sexp c_library_flags.sexp) (action (run ./config/discover.exe))) ocaml-samplerate-0.1.6/src/samplerate.ml000066400000000000000000000021251410232374300202210ustar00rootroot00000000000000type converter = | Conv_sinc_best_quality | Conv_sinc_medium_quality | Conv_fastest | Conv_zero_order_hold | Conv_linear external get_conv_name : converter -> string = "ocaml_samplerate_get_conv_name" external get_conv_descr : converter -> string = "ocaml_samplerate_get_conv_descr" external convert : converter -> int -> float -> float array -> int -> int -> float array = "ocaml_samplerate_convert_byte" "ocaml_samplerate_convert" type t external create : converter -> int -> t = "ocaml_samplerate_new" external process : t -> float -> float array -> int -> int -> float array -> int -> int -> int * int = "ocaml_samplerate_process_byte" "ocaml_samplerate_process" external process_ba : t -> float -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t -> int * int = "ocaml_samplerate_process_ba" external process_alloc : t -> float -> float array -> int -> int -> float array = "ocaml_samplerate_process_alloc" external reset : t -> unit = "ocaml_samplerate_reset" ocaml-samplerate-0.1.6/src/samplerate.mli000066400000000000000000000056571410232374300204070ustar00rootroot00000000000000(** Bindings for libsamplerate library, which is dedicated to changing the sampling rate of audio data. All offsets and sizes are given in number of samples {i per channel}. @author Samuel Mimram *) (** Kind of converter. *) type converter = | Conv_sinc_best_quality (** This is a bandlimited interpolator derived from the mathematical sinc function and this is the highest quality sinc based converter, providing a worst case Signal-to-Noise Ratio (SNR) of 97 decibels (dB) at a bandwidth of 97%. All three Conv_sinc_* converters are based on the techniques of Julius O. Smith although this code was developed independantly. *) | Conv_sinc_medium_quality (** This is another bandlimited interpolator much like the previous one. It has an SNR of 97dB and a bandwidth of 90%. The speed of the conversion is much faster than the previous one. *) | Conv_fastest (** This is the fastest bandlimited interpolator and has an SNR of 97dB and a bandwidth of 80%. *) | Conv_zero_order_hold (** A Zero Order Hold converter (interpolated value is equal to the last value). The quality is poor but the conversion speed is blindlingly fast. *) | Conv_linear (** A linear converter. Again the quality is poor, but the conversion speed is blindingly fast. *) (** Name of a converter. *) val get_conv_name : converter -> string (** Description of a converter. *) val get_conv_descr : converter -> string (** {2 Simple API} *) (** [convert converter channels ratio inbuf offset length] converts audio data with given number of channels with the given ratio (output samplerate / input samplerate) reading from given buffer starting at given offset, the given number of audio samples (per channel). *) val convert : converter -> int -> float -> float array -> int -> int -> float array (** {2 Full API} *) (** Internal state for a converter. *) type t (** Create a converter of given kind with given number of channels. *) val create : converter -> int -> t (** Convert audio data with given state, at given ratio, reading from given buffer at given offset the given number of samples, writing in output buffer starting at offset the given number of samples. Returns the number of samples (per channel) used from input buffer and produced in output buffer. *) val process : t -> float -> float array -> int -> int -> float array -> int -> int -> int * int (** Similar to [process] but takes bigarrays to store audio data. *) val process_ba : t -> float -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t -> (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array1.t -> int * int (** Similar to [process] but allocates a new buffer instead of writing in a specified output buffer. *) val process_alloc : t -> float -> float array -> int -> int -> float array (** Reset the state of the encoder. *) val reset : t -> unit ocaml-samplerate-0.1.6/src/samplerate_stubs.c000066400000000000000000000166571410232374300212720ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #define Int_conv(c) Int_val(c) CAMLprim value ocaml_samplerate_get_conv_name(value conv) { return caml_copy_string(src_get_name(Int_conv(conv))); } CAMLprim value ocaml_samplerate_get_conv_descr(value conv) { return caml_copy_string(src_get_description(Int_conv(conv))); } CAMLprim value ocaml_samplerate_convert(value vconv, value vchans, value vratio, value vinbuf, value inofs, value len) { CAMLparam2(vratio, vinbuf); int chans = Int_val(vchans); float ratio = Double_val(vratio); int inbuflen = Int_val(len); float *inbuf = (float *)malloc(sizeof(float) * inbuflen * chans); int outbuflen = (int)(inbuflen * ratio) + 64; float *outbuf = (float *)malloc(sizeof(float) * outbuflen * chans); SRC_DATA src_data; int i, ret; value ans; int anslen; for (i = 0; i < inbuflen * chans; i++) inbuf[i] = Double_field(vinbuf, i + Int_val(inofs)); src_data.data_in = inbuf; src_data.input_frames = inbuflen; src_data.data_out = outbuf; src_data.output_frames = outbuflen; src_data.src_ratio = ratio; caml_enter_blocking_section(); ret = src_simple(&src_data, Int_val(vconv), chans); caml_leave_blocking_section(); free(inbuf); if (ret != 0) { fprintf(stderr, "ocaml-samplerate (%d): %s\n", ret, src_strerror(ret)); assert(ret == 0); } assert(src_data.input_frames_used == src_data.input_frames); anslen = src_data.output_frames_gen * chans; ans = caml_alloc(anslen * Double_wosize, Double_array_tag); for (i = 0; i < anslen; i++) Store_double_field(ans, i, outbuf[i]); free(outbuf); CAMLreturn(ans); } CAMLprim value ocaml_samplerate_convert_byte(value *argv, int argc) { return ocaml_samplerate_convert(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); } #define State_val(v) (*((SRC_STATE **)Data_custom_val(v))) static void finalize_src(value s) { src_delete(State_val(s)); } static struct custom_operations state_ops = { "ocaml_samplerate_state", finalize_src, custom_compare_default, custom_hash_default, custom_serialize_default, custom_deserialize_default}; CAMLprim value ocaml_samplerate_new(value converter, value channels) { CAMLparam2(converter, channels); int err; SRC_STATE *state = src_new(Int_val(converter), Int_val(channels), &err); value ans; ans = caml_alloc_custom(&state_ops, sizeof(SRC_STATE *), 1, 0); assert(state); /* TODO: raise depending on err */ State_val(ans) = state; CAMLreturn(ans); } CAMLprim value ocaml_samplerate_process(value src, value _ratio, value _inbuf, value _inbufofs, value _inbuflen, value _outbuf, value _outbufofs, value _outbuflen) { CAMLparam4(src, _ratio, _inbuf, _outbuf); CAMLlocal1(ans); SRC_DATA data; SRC_STATE *state = State_val(src); int channels = src_get_channels(state); int inbufofs = Int_val(_inbufofs) * channels; int inbuflen = Int_val(_inbuflen); int outbufofs = Int_val(_outbufofs) * channels; int outbuflen = Int_val(_outbuflen); float *inbuf, *outbuf; int i; inbuf = malloc(inbuflen * channels * sizeof(float)); if (inbuf == NULL) caml_raise_out_of_memory(); for (i = 0; i < inbuflen * channels; i++) inbuf[i] = Double_field(_inbuf, inbufofs + i); data.src_ratio = Double_val(_ratio); caml_release_runtime_system(); outbuf = malloc(outbuflen * channels * sizeof(float)); if (outbuf == NULL) { free(inbuf); caml_acquire_runtime_system(); caml_raise_out_of_memory(); } data.data_in = inbuf; data.input_frames = inbuflen; data.data_out = outbuf; data.output_frames = outbuflen; if (inbuflen == 0) data.end_of_input = 1; else data.end_of_input = 0; int ret = src_process(state, &data); free(inbuf); caml_acquire_runtime_system(); if (ret != 0) { free(outbuf); char msg[256]; snprintf(msg, sizeof(msg), "Samplerate.process: %s", src_strerror(ret)); caml_failwith(msg); } for (i = 0; i < data.output_frames_gen * channels; i++) Store_double_field(_outbuf, outbufofs + i, outbuf[i]); free(outbuf); ans = caml_alloc_tuple(2); Store_field(ans, 0, Val_int(data.input_frames_used)); Store_field(ans, 1, Val_int(data.output_frames_gen)); CAMLreturn(ans); } CAMLprim value ocaml_samplerate_process_byte(value *argv, int argc) { return ocaml_samplerate_process(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); } CAMLprim value ocaml_samplerate_process_ba(value src, value _ratio, value _inbuf, value _outbuf) { CAMLparam4(src, _ratio, _inbuf, _outbuf); CAMLlocal1(ans); SRC_DATA data; SRC_STATE *state = State_val(src); int channels = src_get_channels(state); float ratio = Double_val(_ratio); struct caml_ba_array *inba = Caml_ba_array_val(_inbuf); struct caml_ba_array *outba = Caml_ba_array_val(_outbuf); caml_release_runtime_system(); data.data_in = inba->data; data.input_frames = inba->dim[0] / channels; data.data_out = outba->data; data.output_frames = outba->dim[0] / channels; data.src_ratio = ratio; if (data.input_frames == 0) data.end_of_input = 1; else data.end_of_input = 0; int ret = src_process(state, &data); caml_acquire_runtime_system(); if (ret != 0) caml_failwith(src_strerror(ret)); ans = caml_alloc_tuple(2); Store_field(ans, 0, Val_int(data.input_frames_used)); Store_field(ans, 1, Val_int(data.output_frames_gen)); CAMLreturn(ans); } CAMLprim value ocaml_samplerate_process_alloc(value src, value _ratio, value _inbuf, value _inbufofs, value _inbuflen) { CAMLparam3(src, _ratio, _inbuf); CAMLlocal1(ans); SRC_DATA data; SRC_STATE *state = State_val(src); int channels = src_get_channels(state); int inbufofs = Int_val(_inbufofs) * channels; int inbuflen = Int_val(_inbuflen); float ratio = Double_val(_ratio); int outbuflen = (int)(inbuflen * ratio) + 64; int anslen; float *inbuf, *outbuf; int i; inbuf = malloc(inbuflen * channels * sizeof(float)); if (inbuf == NULL) caml_raise_out_of_memory(); for (i = 0; i < inbuflen * channels; i++) inbuf[i] = Double_field(_inbuf, inbufofs + i); outbuf = malloc(outbuflen * channels * sizeof(float)); if (outbuf == NULL) { free(inbuf); caml_raise_out_of_memory(); } data.data_in = inbuf; data.input_frames = inbuflen; data.data_out = outbuf; data.output_frames = outbuflen; data.src_ratio = ratio; if (inbuflen == 0) data.end_of_input = 1; else data.end_of_input = 0; caml_release_runtime_system(); int ret = src_process(state, &data); caml_acquire_runtime_system(); free(inbuf); if (ret != 0) { free(outbuf); caml_failwith(src_strerror(ret)); } anslen = data.output_frames_gen * channels; ans = caml_alloc(anslen * Double_wosize, Double_array_tag); for (i = 0; i < anslen; i++) Store_double_field(ans, i, outbuf[i]); free(outbuf); CAMLreturn(ans); } CAMLprim value ocaml_samplerate_reset(value src) { src_reset(State_val(src)); return Val_unit; }