Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
205 lines (160 sloc) 4.52 KB
/*
* OCaml bindings for libshine
*
* Copyright 2005-2010 Savonet team
*
* This file is part of ocaml-shine.
*
* ocaml-shine 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-shine 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-shine; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* OCaml bindings for the libshine library. */
#include <caml/custom.h>
#include <caml/signals.h>
#include <caml/misc.h>
#include <caml/memory.h>
#include <caml/fail.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <shine/layer3.h>
#include <string.h>
#include "config.h"
#define Encoder_val(v) (*((shine_t*)Data_custom_val(v)))
static void finalize_encoder(value e)
{
shine_close(Encoder_val(e));
}
static struct custom_operations encoder_ops =
{
"ocaml_shine_encoder",
finalize_encoder,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
CAMLprim value ocaml_shine_samples_per_pass(value e)
{
CAMLparam1(e);
CAMLreturn(Val_int(shine_samples_per_pass(Encoder_val(e))));
}
CAMLprim value ocaml_shine_check_config(value samplerate, value bitrate)
{
CAMLparam0();
if (shine_check_config(Int_val(samplerate), Int_val(bitrate)) < 0)
CAMLreturn(Val_false);
CAMLreturn(Val_true);
}
CAMLprim value ocaml_shine_init(value chans, value samplerate, value bitrate)
{
CAMLparam0();
CAMLlocal1(ans);
shine_config_t config;
shine_t enc;
shine_set_config_mpeg_defaults(&config.mpeg);
config.wave.channels = Int_val(chans);
config.wave.samplerate = Int_val(samplerate);
config.mpeg.bitr = Int_val(bitrate);
if (config.wave.channels == 1)
config.mpeg.mode = MONO;
else
config.mpeg.mode = JOINT_STEREO;
enc = shine_initialise(&config);
if (enc == NULL)
caml_raise_out_of_memory();
ans = caml_alloc_custom(&encoder_ops, sizeof(shine_t), 1, 0);
Encoder_val(ans) = enc;
CAMLreturn(ans);
}
static inline int16_t clip(double s)
{
if (s < -1)
{
return INT16_MIN;
}
else if (s > 1)
{
return INT16_MAX;
}
else
return (s * INT16_MAX);
}
CAMLprim value ocaml_shine_encode_float(value e, value data)
{
CAMLparam2(e,data);
CAMLlocal2(src,ret);
int16_t *pcm[2];
int16_t chan1[SHINE_MAX_SAMPLES], chan2[SHINE_MAX_SAMPLES];
int c,i;
int written;
unsigned char *outdata;
shine_t enc = Encoder_val(e);
pcm[0] = chan1, pcm[1] = chan2;
for (c = 0; c < Wosize_val(data); c++)
{
src = Field(data, c);
for (i = 0; i < shine_samples_per_pass(enc); i++)
{
pcm[c][i] = clip(Double_field(src, i));
}
}
caml_enter_blocking_section();
outdata = shine_encode_buffer(enc, pcm, &written);
caml_leave_blocking_section();
ret = caml_alloc_string(written);
memcpy(String_val(ret),outdata,written);
CAMLreturn(ret);
}
#ifdef BIGENDIAN
static inline int16_t bswap_16 (int16_t x) { return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); }
void swap_buffer(int16_t *sample_buffer, int length)
{
int i;
for (i=0; i<length; i++)
sample_buffer[i] = bswap_16(sample_buffer[i]);
}
#endif
CAMLprim value ocaml_shine_encode_s16le(value e, value data, value channels)
{
CAMLparam2(e,data);
CAMLlocal1(ret);
int16_t pcm[2*SHINE_MAX_SAMPLES];
int16_t *src = (int16_t *)String_val(data);
int written;
int chans = Int_val(channels);
unsigned char *outdata;
shine_t enc = Encoder_val(e);
memcpy(pcm, src, chans*shine_samples_per_pass(enc)*sizeof(int16_t));
caml_enter_blocking_section();
#ifdef BIGENDIAN
swap_buffer(pcm, chans*shine_samples_per_pass(enc));
#endif
outdata = shine_encode_buffer_interleaved(enc, pcm, &written);
caml_leave_blocking_section();
ret = caml_alloc_string(written);
memcpy(String_val(ret),outdata,written);
CAMLreturn(ret);
}
CAMLprim value ocaml_shine_flush(value e)
{
CAMLparam1(e);
CAMLlocal1(ret);
int written;
unsigned char *outdata;
shine_t enc = Encoder_val(e);
outdata = shine_flush(enc,&written);
ret = caml_alloc_string(written);
memcpy(String_val(ret),outdata,written);
CAMLreturn(ret);
}