Closed tribusonz-2 closed 3 months ago
I had an implementation plan to use Ruby's pack/unpack C API to handle digitizers. in C level, as follows:
// for Encode static VALUE test_intle2bytes(VALUE unused_obj, VALUE num, VALUE bytesize) { static char s[4]; size_t sz = NUM2SIZET(bytesize); if (TYPE(num) != T_FIXNUM) num = rb_to_int(num); if (sz > 4) sz = 4; rb_integer_pack(num, s, sz, 8, 1, INTEGER_PACK_LITTLE_ENDIAN | INTEGER_PACK_2COMP); return rb_str_new(s, (long)sz); } // for Decode, to signed value static VALUE test_bytes2intle(VALUE unused_obj, VALUE buf) { char *s = StringValuePtr(buf); return rb_integer_unpack(s, RSTRING_LEN(buf), 1, 0, INTEGER_PACK_LITTLE_ENDIAN | INTEGER_PACK_2COMP); }
It has very good processing speed. However, in practice, it seems faster to combine the digitizer and normalizer.
The decoding, as follows:
void pcm_read_8bit(unsigned char buf[], double s[]) { char data = (buf[0] - 128); *s = data / (double)0x80; } void pcm_read_16bit(unsigned char buf[], double s[]) { int16_t data = (int16_t)(buf[0] | buf[1] << 8); *s = data / (double)0x8000; } void pcm_read_24bit(unsigned char buf[], double s[]) { int data = (buf[0] | buf[1] << 8 | buf[2] << 16); if (data & 0x800000) data -= 0x1000000; *s = data / (double)0x800000; } void pcm_read_32bit(unsigned char buf[], double s[]) { int32_t data = (int32_t)(buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); *s = data / (double)0x80000000; }
In encoding, the normalizer requires guarantees that the values are reliably digitized. This requires the skills of a programmer.
My implementation example is below. First, normalize to ensure digitization, cast to an integer, and write this.
static inline double fclip(double x, double min, double max) { return fmin(fmax(min, x), max); } static inline double wave_normalize(double x, double min, double max, double rate) { if (x != x) x = 0; return fclip(x * rate, min, max); } void pcm_write_8bit(unsigned char buf[], double s[]) { double digitize = wave_normalize(s[0], INT8_MIN, INT8_MAX, 0x80); *buf = (unsigned char)(digitize + 0x80); } void pcm_write_16bit(unsigned char buf[], double s[]) { double digitize = wave_normalize(s[0], INT16_MIN, INT16_MAX, 0x8000); int16_t bytes = (int16_t)digitize; buf[0] = bytes & 0xFF; buf[1] = (bytes >> 8) & 0xFF; } void pcm_write_24bit(unsigned char buf[], double s[]) { double digitize = wave_normalize(s[0], -0x800000, 0x7FFFFF, 0x800000); int32_t bytes = (int32_t)digitize; buf[0] = bytes & 0xFF; buf[1] = (bytes >> 8) & 0xFF; buf[2] = (bytes >> 16) & 0xFF; } void pcm_write_32bit(unsigned char buf[], double s[]) { double digitize = wave_normalize(s[0], INT32_MIN, INT32_MAX, 0x80000000); int32_t bytes = (int32_t)digitize; buf[0] = bytes & 0xFF; buf[1] = (bytes >> 8) & 0xFF; buf[2] = (bytes >> 16) & 0xFF; buf[3] = (bytes >> 24) & 0xFF; }
I had an implementation plan to use Ruby's pack/unpack C API to handle digitizers.
in C level, as follows:
It has very good processing speed.
However, in practice, it seems faster to combine the digitizer and normalizer.
The decoding, as follows:
In encoding, the normalizer requires guarantees that the values are reliably digitized.
This requires the skills of a programmer.
My implementation example is below.
First, normalize to ensure digitization, cast to an integer, and write this.