summaryrefslogtreecommitdiff
path: root/libadpcm
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libadpcm
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libadpcm')
-rw-r--r--libadpcm/Makefile26
-rw-r--r--libadpcm/adpcm.c251
-rw-r--r--libadpcm/adpcm.h13
3 files changed, 290 insertions, 0 deletions
diff --git a/libadpcm/Makefile b/libadpcm/Makefile
new file mode 100644
index 0000000..65453a6
--- /dev/null
+++ b/libadpcm/Makefile
@@ -0,0 +1,26 @@
+# Makefile for libadpcm
+
+include ../Makefile.cfg
+
+AR = mipsel-unknown-elf-ar
+RANLIB = mipsel-unknown-elf-ranlib
+CFLAGS += -O3 -I../libm
+
+all: libadpcm.a
+
+adpcm.o: adpcm.c
+ $(CC) $(CFLAGS) -c adpcm.c
+
+libadpcm.a: adpcm.o
+ rm -f libadpcm.a
+ $(AR) r libadpcm.a adpcm.o
+ $(RANLIB) libadpcm.a
+
+install: all
+ cp libadpcm.a $(TOOLCHAIN_PREFIX)/lib
+ cp adpcm.h $(TOOLCHAIN_PREFIX)/include
+
+clean:
+ rm -f *.o *.a
+
+distclean: clean
diff --git a/libadpcm/adpcm.c b/libadpcm/adpcm.c
new file mode 100644
index 0000000..5269316
--- /dev/null
+++ b/libadpcm/adpcm.c
@@ -0,0 +1,251 @@
+/*
+ * PCM -> ADPCM routines
+ *
+ * based on work by Bitmaster and extended
+ */
+
+// The version here was converted by double to ints, and so
+// it loses much precision... but if that wasn't done it would have
+// a very bad performance on the PlayStation hardware
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <math.h>
+#include <psx.h>
+#include "adpcm.h"
+
+#define PCM_BUFFER_SIZE 128*28
+
+short pcm_buffer[PCM_BUFFER_SIZE];
+
+void SsAdpcm_find_predict( short *samples, int *d_samples, int *predict_nr, int *shift_factor);
+void SsAdpcm_pack( int *d_samples, short *four_bit, int predict_nr, int shift_factor);
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping)
+{
+ short *ptr;
+ unsigned char *pcm_data_c = pcm_data;
+ short *pcm_data_s = pcm_data;
+ unsigned char *adpcm_data_c = adpcm_data;
+ int d_samples[28];
+ short four_bit[28];
+ int predict_nr;
+ int shift_factor;
+ int flags;
+ int size;
+ int i, j, k;
+ unsigned char d;
+ int ap = 0;
+
+/*printf("pcm_data = %x, adpcm_data = %x, len = %x, fmt = %x, alen = %x,"
+ "loop = %x\n", pcm_data, adpcm_data, sample_len, sample_fmt,
+ adpcm_len, enable_looping);
+ for(i=0;i<8;i++)
+ printf("I[%d] = %x\n", i, pcm_data_c[i]);*/
+
+ if(enable_looping)
+ flags = 6;
+ else
+ flags = 0;
+
+ //sample_len -= sample_len % 28;
+
+while( sample_len > 0 ) {
+ size = ( sample_len >= PCM_BUFFER_SIZE ) ? PCM_BUFFER_SIZE : sample_len;
+
+ if(sample_fmt == FMT_U8)
+ {
+ for(i = 0; i < size; i++)
+ {
+ //c = fgetc(fp);
+ pcm_buffer[i] = *(pcm_data_c++);
+ pcm_buffer[i] ^= 0x80;
+ pcm_buffer[i] <<= 8;
+ }
+ }
+ else if(sample_fmt == FMT_S16)
+ {
+ //fread( wave, sizeof( short ), size, fp );
+ memcpy(pcm_buffer, pcm_data_s, size * sizeof(short));
+ pcm_data_s += size;
+ }
+ else
+ {
+ printf("%s, line %d: Unknown source sample format!, id=%d\n",__FUNCTION__,__LINE__,sample_fmt);
+ return 0;
+ }
+
+ i = size / 28;
+ if ( size % 28 ) {
+ for ( j = size % 28; j < 28; j++ )
+ pcm_buffer[28*i+j] = 0;
+ i++;
+ }
+
+ for ( j = 0; j < i; j++ ) { // pack 28 samples
+ ptr = pcm_buffer + j * 28;
+ SsAdpcm_find_predict( ptr, d_samples, &predict_nr, &shift_factor );
+ SsAdpcm_pack( d_samples, four_bit, predict_nr, shift_factor );
+ d = ( predict_nr << 4 ) | shift_factor;
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ // fputc( flags, vag );
+ adpcm_data_c[ap++] = flags;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ for ( k = 0; k < 28; k += 2 ) {
+ d = ( ( four_bit[k+1] >> 8 ) & 0xf0 ) | ( ( four_bit[k] >> 12 ) & 0xf );
+ // fputc( d, vag );
+ adpcm_data_c[ap++] = d;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+ }
+ sample_len -= 28;
+ if ( sample_len < 28 && enable_looping == 0)
+ flags = 1;
+
+ if(enable_looping)
+ flags = 2;
+ }
+ }
+
+ // fputc( ( predict_nr << 4 ) | shift_factor, vag );
+ adpcm_data_c[ap++] = ( predict_nr << 4 ) | shift_factor;
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ if(enable_looping == 1)
+ // fputc(3, vag);
+ adpcm_data_c[ap++] = 3;
+ else if(enable_looping == 2)
+ adpcm_data_c[ap++] = 0;
+ else if(enable_looping == 3)
+ adpcm_data_c[ap++] = 2;
+ else
+// fputc( 7, vag ); // end flag
+ adpcm_data_c[ap++] = 7;
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ if(enable_looping != 2)
+ {
+ for ( i = 0; i < 14; i++ )
+ // fputc( 0, vag );
+ adpcm_data_c[ap++] = 0;
+ }
+
+ if(ap>=adpcm_len) goto adpcm_too_big;
+
+ return ap;
+
+adpcm_too_big:
+ printf("%s: Resulting ADPCM data would have been larger than the output array length! Exiting %s.\n", __FUNCTION__, __FUNCTION__);
+ return 0;
+}
+
+
+static const int f[5][2] = { { 0, 0 },
+ { 60, 0 },
+ { 115, -52},
+ { 98, -55},
+ { 122, -60} };
+
+void SsAdpcm_find_predict( short *samples, int *d_samples, int *predict_nr, int *shift_factor )
+{
+ int i, j;
+ int buffer[28][5];
+ int min = 0x7fffffff;
+ int max[5];
+ int ds;
+ int min2;
+ int shift_mask;
+ static int _s_1 = 0; // s[t-1]
+ static int _s_2 = 0; // s[t-2]
+ int s_0, s_1, s_2;
+
+
+ for ( i = 0; i < 5; i++ ) {
+ max[i] = 0.0;
+ s_1 = _s_1;
+ s_2 = _s_2;
+ for ( j = 0; j < 28; j ++ ) {
+ s_0 = (int) samples[j]; // s[t-0]
+ if ( s_0 > 32767 )
+ s_0 = 32767;
+ if ( s_0 < - 32768 )
+ s_0 = -32768;
+ ds = s_0 + s_1 * f[i][0] + s_2 * f[i][1];
+ buffer[j][i] = ds;
+ if ( ds > max[i] )
+ max[i] = ds;
+// printf( "%+5.2f\n", s2 );
+ s_2 = s_1; // new s[t-2]
+ s_1 = s_0; // new s[t-1]
+ }
+
+ if ( max[i] <= min ) {
+ // printf("min = %d, max[i] = %d", min, max[i]);
+ min = max[i];
+ *predict_nr = i;
+ }
+ if ( min <= 7 ) {
+ *predict_nr = 0;
+ break;
+ }
+
+ }
+
+// store s[t-2] and s[t-1] in a static variable
+// these than used in the next function call
+
+ _s_1 = s_1;
+ _s_2 = s_2;
+
+ for ( i = 0; i < 28; i++ )
+ d_samples[i] = buffer[i][*predict_nr];
+
+// if ( min > 32767.0 )
+// min = 32767.0;
+
+ min2 = ( int ) min;
+ shift_mask = 0x4000;
+ *shift_factor = 0;
+
+ while( *shift_factor < 12 ) {
+ if ( shift_mask & ( min2 + ( shift_mask >> 3 ) ) )
+ break;
+ (*shift_factor)++;
+ shift_mask = shift_mask >> 1;
+ }
+
+}
+
+void SsAdpcm_pack( int *d_samples, short *four_bit, int predict_nr, int shift_factor )
+{
+ int ds;
+ int di;
+ int s_0;
+ static int s_1 = 0;
+ static int s_2 = 0;
+ int i;
+
+ for ( i = 0; i < 28; i++ ) {
+ s_0 = d_samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
+ ds = s_0 * (int) ( 1 << shift_factor );
+
+ di = ( (int) ds + 0x800 ) & 0xfffff000;
+
+ if ( di > 32767 )
+ di = 32767;
+ if ( di < -32768 )
+ di = -32768;
+
+ four_bit[i] = (short) di;
+
+ di = di >> shift_factor;
+ s_2 = s_1;
+ s_1 = (int) di - s_0;
+
+ }
+}
diff --git a/libadpcm/adpcm.h b/libadpcm/adpcm.h
new file mode 100644
index 0000000..8070512
--- /dev/null
+++ b/libadpcm/adpcm.h
@@ -0,0 +1,13 @@
+#ifndef _PSX_ADPCM_H
+#define _PSX_ADPCM_H
+
+enum
+{
+ FMT_U8, // unsigned 8-bit
+ FMT_S16, // signed 16-bit
+};
+
+int SsAdpcmPack(void *pcm_data, void *adpcm_data, int sample_len,
+ int sample_fmt, int adpcm_len, int enable_looping);
+
+#endif \ No newline at end of file