From 4d6306eb4da8cdac4b5dee9784959672c233eec8 Mon Sep 17 00:00:00 2001 From: Guilhem Lavaux Date: Mon, 9 Nov 1998 18:37:38 +0000 Subject: [PATCH] * Added wxMMedia in the repository so people interrested in it can work on it * WARNING! It is quite unstable on Windows and it doesn't work on Linux for the moment because I didn't finish fixing the CODEC stream. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@975 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- utils/wxMMedia/Makefile | 1 + utils/wxMMedia/Makefile.in | 38 ++ utils/wxMMedia/adpcm/g711.cpp | 283 ++++++++++++++ utils/wxMMedia/adpcm/g721.cpp | 173 +++++++++ utils/wxMMedia/adpcm/g723_24.cpp | 158 ++++++++ utils/wxMMedia/adpcm/g723_40.cpp | 178 +++++++++ utils/wxMMedia/adpcm/g72x.cpp | 608 +++++++++++++++++++++++++++++++ utils/wxMMedia/adpcm/g72x.h | 123 +++++++ utils/wxMMedia/cdbase.cpp | 52 +++ utils/wxMMedia/cdbase.h | 88 +++++ utils/wxMMedia/cdunix.cpp | 198 ++++++++++ utils/wxMMedia/cdunix.h | 61 ++++ utils/wxMMedia/cdwin.cpp | 208 +++++++++++ utils/wxMMedia/cdwin.h | 67 ++++ utils/wxMMedia/mmdata.cpp | 92 +++++ utils/wxMMedia/mmedia.h | 31 ++ utils/wxMMedia/mmfile.cpp | 194 ++++++++++ utils/wxMMedia/mmfile.h | 94 +++++ utils/wxMMedia/mmriff.cpp | 215 +++++++++++ utils/wxMMedia/mmriff.h | 81 ++++ utils/wxMMedia/mmsolve.cpp | 124 +++++++ utils/wxMMedia/mmsolve.h | 92 +++++ utils/wxMMedia/mmtype.h | 41 +++ utils/wxMMedia/sndaiff.cpp | 218 +++++++++++ utils/wxMMedia/sndaiff.h | 58 +++ utils/wxMMedia/sndau.cpp | 114 ++++++ utils/wxMMedia/sndau.h | 47 +++ utils/wxMMedia/sndfile.cpp | 323 ++++++++++++++++ utils/wxMMedia/sndfile.h | 91 +++++ utils/wxMMedia/sndfrag.cpp | 268 ++++++++++++++ utils/wxMMedia/sndfrag.h | 103 ++++++ utils/wxMMedia/sndfrmt.cpp | 266 ++++++++++++++ utils/wxMMedia/sndfrmt.h | 119 ++++++ utils/wxMMedia/sndmulaw.cpp | 85 +++++ utils/wxMMedia/sndmulaw.h | 28 ++ utils/wxMMedia/sndpcm.cpp | 216 +++++++++++ utils/wxMMedia/sndpcm.h | 39 ++ utils/wxMMedia/sndsnd.cpp | 264 ++++++++++++++ utils/wxMMedia/sndsnd.h | 275 ++++++++++++++ utils/wxMMedia/snduss.cpp | 268 ++++++++++++++ utils/wxMMedia/snduss.h | 85 +++++ utils/wxMMedia/sndwav.cpp | 186 ++++++++++ utils/wxMMedia/sndwav.h | 59 +++ utils/wxMMedia/sndwin.cpp | 384 +++++++++++++++++++ utils/wxMMedia/sndwin.h | 108 ++++++ utils/wxMMedia/ulaw.h | 69 ++++ utils/wxMMedia/vidbase.cpp | 87 +++++ utils/wxMMedia/vidbase.h | 105 ++++++ utils/wxMMedia/vidwin.cpp | 131 +++++++ utils/wxMMedia/vidwin.h | 62 ++++ utils/wxMMedia/vidxanm.cpp | 231 ++++++++++++ utils/wxMMedia/vidxanm.h | 69 ++++ utils/wxMMedia/wave.cpp | 65 ++++ utils/wxMMedia/wave.h | 43 +++ 54 files changed, 7666 insertions(+) create mode 100644 utils/wxMMedia/Makefile create mode 100644 utils/wxMMedia/Makefile.in create mode 100644 utils/wxMMedia/adpcm/g711.cpp create mode 100644 utils/wxMMedia/adpcm/g721.cpp create mode 100644 utils/wxMMedia/adpcm/g723_24.cpp create mode 100644 utils/wxMMedia/adpcm/g723_40.cpp create mode 100644 utils/wxMMedia/adpcm/g72x.cpp create mode 100644 utils/wxMMedia/adpcm/g72x.h create mode 100644 utils/wxMMedia/cdbase.cpp create mode 100644 utils/wxMMedia/cdbase.h create mode 100644 utils/wxMMedia/cdunix.cpp create mode 100644 utils/wxMMedia/cdunix.h create mode 100644 utils/wxMMedia/cdwin.cpp create mode 100644 utils/wxMMedia/cdwin.h create mode 100644 utils/wxMMedia/mmdata.cpp create mode 100644 utils/wxMMedia/mmedia.h create mode 100644 utils/wxMMedia/mmfile.cpp create mode 100644 utils/wxMMedia/mmfile.h create mode 100644 utils/wxMMedia/mmriff.cpp create mode 100644 utils/wxMMedia/mmriff.h create mode 100644 utils/wxMMedia/mmsolve.cpp create mode 100644 utils/wxMMedia/mmsolve.h create mode 100644 utils/wxMMedia/mmtype.h create mode 100644 utils/wxMMedia/sndaiff.cpp create mode 100644 utils/wxMMedia/sndaiff.h create mode 100644 utils/wxMMedia/sndau.cpp create mode 100644 utils/wxMMedia/sndau.h create mode 100644 utils/wxMMedia/sndfile.cpp create mode 100644 utils/wxMMedia/sndfile.h create mode 100644 utils/wxMMedia/sndfrag.cpp create mode 100644 utils/wxMMedia/sndfrag.h create mode 100644 utils/wxMMedia/sndfrmt.cpp create mode 100644 utils/wxMMedia/sndfrmt.h create mode 100644 utils/wxMMedia/sndmulaw.cpp create mode 100644 utils/wxMMedia/sndmulaw.h create mode 100644 utils/wxMMedia/sndpcm.cpp create mode 100644 utils/wxMMedia/sndpcm.h create mode 100644 utils/wxMMedia/sndsnd.cpp create mode 100644 utils/wxMMedia/sndsnd.h create mode 100644 utils/wxMMedia/snduss.cpp create mode 100644 utils/wxMMedia/snduss.h create mode 100644 utils/wxMMedia/sndwav.cpp create mode 100644 utils/wxMMedia/sndwav.h create mode 100644 utils/wxMMedia/sndwin.cpp create mode 100644 utils/wxMMedia/sndwin.h create mode 100644 utils/wxMMedia/ulaw.h create mode 100644 utils/wxMMedia/vidbase.cpp create mode 100644 utils/wxMMedia/vidbase.h create mode 100644 utils/wxMMedia/vidwin.cpp create mode 100644 utils/wxMMedia/vidwin.h create mode 100644 utils/wxMMedia/vidxanm.cpp create mode 100644 utils/wxMMedia/vidxanm.h create mode 100644 utils/wxMMedia/wave.cpp create mode 100644 utils/wxMMedia/wave.h diff --git a/utils/wxMMedia/Makefile b/utils/wxMMedia/Makefile new file mode 100644 index 0000000000..bccce53f76 --- /dev/null +++ b/utils/wxMMedia/Makefile @@ -0,0 +1 @@ +include ../../setup/general/makeapp diff --git a/utils/wxMMedia/Makefile.in b/utils/wxMMedia/Makefile.in new file mode 100644 index 0000000000..e4effa22d3 --- /dev/null +++ b/utils/wxMMedia/Makefile.in @@ -0,0 +1,38 @@ +# WXXT base directory +WXBASEDIR=@WXBASEDIR@ + +# set the OS type for compilation +OS=@OS@ +# compile a library only +RULE=gslib + +# define common stuff + +# define library name +LIB_TARGET=wxmmedia +LIB_MAJOR=2 +LIB_MINOR=0 +# define library sources +ADPCM_SRC=\ +g711.cpp g721.cpp g723_24.cpp g723_40.cpp g72x.cpp + +MMEDIA_SRC=\ +mmdata.cpp mmfile.cpp mmsolve.cpp sndsnd.cpp sndfrmt.cpp sndpcm.o \ +snduss.cpp sndfile.cpp sndwav.cpp mmriff.cpp vidbase.cpp vidxanm.cpp \ +cdbase.cpp cdunix.cpp + +LIB_SRC= $(ADPCM_SRC:%.cpp=adpcm/%.cpp) $(MMEDIA_SRC) + +#define library objects +LIB_OBJ=\ +$(LIB_SRC:%.cpp=%.o) + +#additional things needed for compile +ADD_COMPILE= -I$(UTILS)/wxthread + +all:: + -mkdir -p adpcm + +# include the definitions now +include ../../../template.mak + diff --git a/utils/wxMMedia/adpcm/g711.cpp b/utils/wxMMedia/adpcm/g711.cpp new file mode 100644 index 0000000000..d4d60a5c26 --- /dev/null +++ b/utils/wxMMedia/adpcm/g711.cpp @@ -0,0 +1,283 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g711.c + * + * u-law, A-law and linear PCM conversions. + */ +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; + +/* copy from CCITT G.711 specifications */ +unsigned char _u2a[128] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + +unsigned char _a2u[128] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +static int +search( + int val, + short *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} + +/* + * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * linear2alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char +linear2alaw( + int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 8; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_end, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (0x7F ^ mask); + else { + aval = seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 4) & QUANT_MASK; + else + aval |= (pcm_val >> (seg + 3)) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit linear PCM + * + */ +int +alaw2linear( + unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} + +#define BIAS (0x84) /* Bias for linear code. */ + +/* + * linear2ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char +linear2ulaw( + int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = BIAS - pcm_val; + mask = 0x7F; + } else { + pcm_val += BIAS; + mask = 0xFF; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_end, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (0x7F ^ mask); + else { + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int +ulaw2linear( + unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} + +/* A-law to u-law conversion */ +unsigned char +alaw2ulaw( + unsigned char aval) +{ + aval &= 0xff; + return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) : + (0x7F ^ _a2u[aval ^ 0x55])); +} + +/* u-law to A-law conversion */ +unsigned char +ulaw2alaw( + unsigned char uval) +{ + uval &= 0xff; + return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) : + (0x55 ^ (_u2a[0x7F ^ uval] - 1))); +} diff --git a/utils/wxMMedia/adpcm/g721.cpp b/utils/wxMMedia/adpcm/g721.cpp new file mode 100644 index 0000000000..3411d1a1bb --- /dev/null +++ b/utils/wxMMedia/adpcm/g721.cpp @@ -0,0 +1,173 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g721.c + * + * Description: + * + * g721_encoder(), g721_decoder() + * + * These routines comprise an implementation of the CCITT G.721 ADPCM + * coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of work station attributes, such as hardware 2's + * complement arithmetic and large memory. Specifically, certain time + * consuming operations such as multiplications are replaced + * with lookup tables and software 2's complement operations are + * replaced with hardware 2's complement. + * + * The deviation from the bit level specification (lookup tables) + * preserves the bit level performance specifications. + * + * As outlined in the G.721 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ +#include "g72x.h" + +static short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400}; +/* + * Maps G.721 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425, + 425, 373, 323, 273, 213, 135, 4, -2048}; + +/* Maps G.721 code word to log of scale factor multiplier. */ +static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122, + 1122, 355, 198, 112, 64, 41, 18, -12}; +/* + * Maps G.721 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, + 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; + +/* + * g721_encoder() + * + * Encodes the input vale of linear PCM, A-law or u-law data sl and returns + * the resulting code. -1 is returned for unknown input coding value. + */ +int +g721_encoder( + int sl, + int in_coding, + struct g72x_state *state_ptr) +{ + short sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short sr; /* ADDB */ + short y; /* MIX */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = alaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = ulaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl = ((short)sl) >> 2; /* 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */ + + d = sl - se; /* estimation difference */ + + /* quantize the prediction difference */ + y = step_size(state_ptr); /* quantizer step size */ + i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */ + + dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */ + + dqsez = sr + sez - se; /* pole prediction diff. */ + + update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g721_decoder() + * + * Description: + * + * Decodes a 4-bit code of G.721 encoded data of i and + * returns the resulting linear PCM, A-law or u-law value. + * return -1 for unknown out_coding value. + */ +int +g721_decoder( + int i, + int out_coding, + struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x0f; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* dynamic quantizer step size */ + + dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/utils/wxMMedia/adpcm/g723_24.cpp b/utils/wxMMedia/adpcm/g723_24.cpp new file mode 100644 index 0000000000..ba122eadf3 --- /dev/null +++ b/utils/wxMMedia/adpcm/g723_24.cpp @@ -0,0 +1,158 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_24.c + * + * Description: + * + * g723_24_encoder(), g723_24_decoder() + * + * These routines comprise an implementation of the CCITT G.723 24 Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which take advantage + * of workstation attributes, such as hardware 2's complement arithmetic. + * + */ +#include "g72x.h" + +/* + * Maps G.723_24 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048}; + +/* Maps G.723_24 code word to log of scale factor multiplier. */ +static short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128}; + +/* + * Maps G.723_24 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0}; + +static short qtab_723_24[3] = {8, 218, 331}; + +/* + * g723_24_encoder() + * + * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. + * Returns -1 if invalid input coding value. + */ +int +g723_24_encoder( + int sl, + int in_coding, + struct g72x_state *state_ptr) +{ + short sei, sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short y; /* MIX */ + short sr; /* ADDB */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = alaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = ulaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl = ((short)sl) >> 2; /* sl of 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + d = sl - se; /* d = estimation diff. */ + + /* quantize prediction difference d */ + y = step_size(state_ptr); /* quantizer step size */ + i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */ + dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */ + + dqsez = sr + sez - se; /* pole prediction diff. */ + + update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g723_24_decoder() + * + * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int +g723_24_decoder( + int i, + int out_coding, + struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x07; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* adaptive quantizer step size */ + dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was of 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/utils/wxMMedia/adpcm/g723_40.cpp b/utils/wxMMedia/adpcm/g723_40.cpp new file mode 100644 index 0000000000..b8ec06a686 --- /dev/null +++ b/utils/wxMMedia/adpcm/g723_40.cpp @@ -0,0 +1,178 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_40.c + * + * Description: + * + * g723_40_encoder(), g723_40_decoder() + * + * These routines comprise an implementation of the CCITT G.723 40Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of workstation attributes, such as hardware 2's + * complement arithmetic. + * + * The deviation from the bit level specification (lookup tables), + * preserves the bit level performance specifications. + * + * As outlined in the G.723 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ +#include "g72x.h" + +/* + * Maps G.723_40 code word to ructeconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318, + 358, 395, 429, 459, 488, 514, 539, 566, + 566, 539, 514, 488, 459, 429, 395, 358, + 318, 274, 224, 169, 104, 28, -66, -2048}; + +/* Maps G.723_40 code word to log of scale factor multiplier. */ +static short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200, + 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, + 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, + 3200, 1856, 1312, 1280, 1248, 768, 448, 448}; + +/* + * Maps G.723_40 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, + 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, + 0x200, 0x200, 0x200, 0, 0, 0, 0, 0}; + +static short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339, + 378, 413, 445, 475, 502, 528, 553}; + +/* + * g723_40_encoder() + * + * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens + * the resulting 5-bit CCITT G.723 40Kbps code. + * Returns -1 if the input coding value is invalid. + */ +int +g723_40_encoder( + int sl, + int in_coding, + struct g72x_state *state_ptr) +{ + short sei, sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short y; /* MIX */ + short sr; /* ADDB */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = alaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = ulaw2linear(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl = ((short) sl) >> 2; /* sl of 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + d = sl - se; /* d = estimation difference */ + + /* quantize prediction difference */ + y = step_size(state_ptr); /* adaptive quantizer step size */ + i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */ + + dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */ + + sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */ + + dqsez = sr + sez - se; /* dqsez = pole prediction diff. */ + + update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g723_40_decoder() + * + * Decodes a 5-bit CCITT G.723 40Kbps code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int +g723_40_decoder( + int i, + int out_coding, + struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x1f; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* adaptive quantizer step size */ + dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */ + + sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was of 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/utils/wxMMedia/adpcm/g72x.cpp b/utils/wxMMedia/adpcm/g72x.cpp new file mode 100644 index 0000000000..ff571bdad7 --- /dev/null +++ b/utils/wxMMedia/adpcm/g72x.cpp @@ -0,0 +1,608 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g72x.c + * + * Common routines for G.721 and G.723 conversions. + */ + +#include +#include "g72x.h" + +static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000}; + +/* + * quan() + * + * quantizes the input val against the table of size short integers. + * It returns i if table[i - 1] <= val < table[i]. + * + * Using linear search for simple coding. + */ +static int +quan( + int val, + short *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) + if (val < *table++) + break; + return (i); +} + +static char quan2_tab[65536]; +static short base2_tab[65536]; +static int init_tabs_done = 0; + +inline char quan2 (unsigned short val) +{ + return quan2_tab[val]; +} + +inline short base2 (unsigned short val) +{ + return base2_tab[val]; +} + +static void init_quan2_tab (void) +{ + long i; + + for (i = 0; i < 65536; i++) { + quan2_tab[i] = quan (i, power2, 15); + }; +} + +static void init_base2_tab (void) +{ + long i; + short exp; + + for (i = 0; i < 65536; i++) { + exp = quan2 (short (i)); + base2_tab[i] = short ((exp << 6) + ((i << 6) >> exp)); + }; +} + +static void init_tabs (void) +{ + if (init_tabs_done) return; + + init_quan2_tab(); + init_base2_tab(); + + init_tabs_done = 1; +} + +/* + * fmult() + * + * returns the integer product of the 14-bit integer "an" and + * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". + */ +static int +fmult( + int an, + int srn) +{ + short anmag, anexp, anmant; + short wanexp, wanmant; + short retval; + + anmag = (an > 0) ? an : ((-an) & 0x1FFF); + anexp = quan2(anmag) - 6; + anmant = (anmag == 0) ? 32 : + (anexp >= 0) ? anmag >> anexp : anmag << -anexp; + wanexp = anexp + ((srn >> 6) & 0xF) - 13; + + wanmant = (anmant * (srn & 077) + 0x30) >> 4; + retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : + (wanmant >> -wanexp); + + return (((an ^ srn) < 0) ? -retval : retval); +} + +/* + * g72x_init_state() + * + * This routine initializes and/or resets the g72x_state structure + * pointed to by 'state_ptr'. + * All the initial state values are specified in the CCITT G.721 document. + */ +void +g72x_init_state( + struct g72x_state *state_ptr) +{ + int cnta; + + init_tabs (); + + state_ptr->yl = 34816; + state_ptr->yu = 544; + state_ptr->dms = 0; + state_ptr->dml = 0; + state_ptr->ap = 0; + for (cnta = 0; cnta < 2; cnta++) { + state_ptr->a[cnta] = 0; + state_ptr->pk[cnta] = 0; + state_ptr->sr[cnta] = 32; + } + for (cnta = 0; cnta < 6; cnta++) { + state_ptr->b[cnta] = 0; + state_ptr->dq[cnta] = 32; + } + state_ptr->td = 0; +} + +/* + * predictor_zero() + * + * computes the estimated signal from 6-zero predictor. + * + */ +int +predictor_zero( + struct g72x_state *state_ptr) +{ + int i; + int sezi; + + sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]); + for (i = 1; i < 6; i++) /* ACCUM */ + sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]); + return (sezi); +} +/* + * predictor_pole() + * + * computes the estimated signal from 2-pole predictor. + * + */ +int +predictor_pole( + struct g72x_state *state_ptr) +{ + return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) + + fmult(state_ptr->a[0] >> 2, state_ptr->sr[0])); +} +/* + * step_size() + * + * computes the quantization step size of the adaptive quantizer. + * + */ +int +step_size( + struct g72x_state *state_ptr) +{ + int y; + int dif; + int al; + + if (state_ptr->ap >= 256) + return (state_ptr->yu); + else { + y = state_ptr->yl >> 6; + dif = state_ptr->yu - y; + al = state_ptr->ap >> 2; + if (dif > 0) + y += (dif * al) >> 6; + else if (dif < 0) + y += (dif * al + 0x3F) >> 6; + return (y); + } +} + +/* + * quantize() + * + * Given a raw sample, 'd', of the difference signal and a + * quantization step size scale factor, 'y', this routine returns the + * ADPCM codeword to which that sample gets quantized. The step + * size scale factor division operation is done in the log base 2 domain + * as a subtraction. + */ +int +quantize( + int d, /* Raw difference signal sample */ + int y, /* Step size multiplier */ + short *table, /* quantization table */ + int size) /* table size of short integers */ +{ + short dqm; /* Magnitude of 'd' */ + short exp; /* Integer part of base 2 log of 'd' */ + short mant; /* Fractional part of base 2 log */ + short dl; /* Log of magnitude of 'd' */ + short dln; /* Step size scale factor normalized log */ + int i; + + /* + * LOG + * + * Compute base 2 log of 'd', and store in 'dl'. + */ + dqm = abs(d); + exp = quan2(dqm >> 1); + mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */ + dl = (exp << 7) + mant; + + /* + * SUBTB + * + * "Divide" by step size multiplier. + */ + dln = dl - (y >> 2); + + /* + * QUAN + * + * Obtain codword i for 'd'. + */ + i = quan(dln, table, size); + if (d < 0) /* take 1's complement of i */ + return ((size << 1) + 1 - i); + else if (i == 0) /* take 1's complement of 0 */ + return ((size << 1) + 1); /* new in 1988 */ + else + return (i); +} +/* + * reconstruct() + * + * Returns reconstructed difference signal 'dq' obtained from + * codeword 'i' and quantization step size scale factor 'y'. + * Multiplication is performed in log base 2 domain as addition. + */ +int +reconstruct( + int sign, /* 0 for non-negative value */ + int dqln, /* G.72x codeword */ + int y) /* Step size multiplier */ +{ + short dql; /* Log of 'dq' magnitude */ + short dex; /* Integer part of log */ + short dqt; + short dq; /* Reconstructed difference signal sample */ + + dql = dqln + (y >> 2); /* ADDA */ + + if (dql < 0) { + return ((sign) ? -0x8000 : 0); + } else { /* ANTILOG */ + dex = (dql >> 7) & 15; + dqt = 128 + (dql & 127); + dq = (dqt << 7) >> (14 - dex); + return ((sign) ? (dq - 0x8000) : dq); + } +} + + +/* + * update() + * + * updates the state variables for each output code + */ +void +update( + int code_size, /* distinguish 723_40 with others */ + int y, /* quantizer step size */ + int wi, /* scale factor multiplier */ + int fi, /* for long/short term energies */ + int dq, /* quantized prediction difference */ + int sr, /* reconstructed signal */ + int dqsez, /* difference from 2-pole predictor */ + struct g72x_state *state_ptr) /* coder state pointer */ +{ + int cnt; + short mag; /* Adaptive predictor, FLOAT A */ + short a2p; /* LIMC */ + short a1ul; /* UPA1 */ + short pks1; /* UPA2 */ + short fa1; + char tr; /* tone/transition detector */ + short ylint, thr2, dqthr; + short ylfrac, thr1; + short pk0; + + pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */ + + mag = dq & 0x7FFF; /* prediction difference magnitude */ + /* TRANS */ + ylint = short (state_ptr->yl >> 15); /* exponent part of yl */ + ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */ + thr1 = (32 + ylfrac) << ylint; /* threshold */ + thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */ + dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */ + if (state_ptr->td == 0) /* signal supposed voice */ + tr = 0; + else if (mag <= dqthr) /* supposed data, but small mag */ + tr = 0; /* treated as voice */ + else /* signal is data (modem) */ + tr = 1; + + /* + * Quantizer scale factor adaptation. + */ + + /* FUNCTW & FILTD & DELAY */ + /* update non-steady state step size multiplier */ + state_ptr->yu = y + ((wi - y) >> 5); + + /* LIMB */ + if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ + state_ptr->yu = 544; + else if (state_ptr->yu > 5120) + state_ptr->yu = 5120; + + /* FILTE & DELAY */ + /* update steady state step size multiplier */ + state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6); + + /* + * Adaptive predictor coefficients. + */ + if (tr == 1) { /* reset a's and b's for modem signal */ + state_ptr->a[0] = 0; + state_ptr->a[1] = 0; + state_ptr->b[0] = 0; + state_ptr->b[1] = 0; + state_ptr->b[2] = 0; + state_ptr->b[3] = 0; + state_ptr->b[4] = 0; + state_ptr->b[5] = 0; + + a2p = 0; /* eliminate Compiler Warnings */ + } else { /* update a's and b's */ + pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */ + + /* update predictor pole a[1] */ + a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7); + if (dqsez != 0) { + fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0]; + if (fa1 < -8191) /* a2p = function of fa1 */ + a2p -= 0x100; + else if (fa1 > 8191) + a2p += 0xFF; + else + a2p += fa1 >> 5; + + if (pk0 ^ state_ptr->pk[1]) + /* LIMC */ + if (a2p <= -12160) + a2p = -12288; + else if (a2p >= 12416) + a2p = 12288; + else + a2p -= 0x80; + else if (a2p <= -12416) + a2p = -12288; + else if (a2p >= 12160) + a2p = 12288; + else + a2p += 0x80; + } + + /* TRIGB & DELAY */ + state_ptr->a[1] = a2p; + + /* UPA1 */ + /* update predictor pole a[0] */ + state_ptr->a[0] -= state_ptr->a[0] >> 8; + if (dqsez != 0) + if (pks1 == 0) + state_ptr->a[0] += 192; + else + state_ptr->a[0] -= 192; + + /* LIMD */ + a1ul = 15360 - a2p; + if (state_ptr->a[0] < -a1ul) + state_ptr->a[0] = -a1ul; + else if (state_ptr->a[0] > a1ul) + state_ptr->a[0] = a1ul; + + /* UPB : update predictor zeros b[6] */ + for (cnt = 0; cnt < 6; cnt++) { + if (code_size == 5) /* for 40Kbps G.723 */ + state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9; + else /* for G.721 and 24Kbps G.723 */ + state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8; + if (dq & 0x7FFF) { /* XOR */ + if ((dq ^ state_ptr->dq[cnt]) >= 0) + state_ptr->b[cnt] += 128; + else + state_ptr->b[cnt] -= 128; + } + } + } + + for (cnt = 5; cnt > 0; cnt--) + state_ptr->dq[cnt] = state_ptr->dq[cnt-1]; + /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ + if (mag == 0) { + state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20; + } else { + state_ptr->dq[0] = (dq >= 0) ? + base2 (mag) : base2 (mag) - 0x400; + } + + state_ptr->sr[1] = state_ptr->sr[0]; + /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ + if (sr == 0) { + state_ptr->sr[0] = 0x20; + } else if (sr > 0) { + state_ptr->sr[0] = base2(sr); + } else if (sr > -32768) { + mag = -sr; + state_ptr->sr[0] = base2(mag) - 0x400; + } else + state_ptr->sr[0] = short (0xFC20); + + /* DELAY A */ + state_ptr->pk[1] = state_ptr->pk[0]; + state_ptr->pk[0] = pk0; + + /* TONE */ + if (tr == 1) /* this sample has been treated as data */ + state_ptr->td = 0; /* next one will be treated as voice */ + else if (a2p < -11776) /* small sample-to-sample correlation */ + state_ptr->td = 1; /* signal may be data */ + else /* signal is voice */ + state_ptr->td = 0; + + /* + * Adaptation speed control. + */ + state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */ + state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */ + + if (tr == 1) + state_ptr->ap = 256; + else if (y < 1536) /* SUBTC */ + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (state_ptr->td == 1) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= + (state_ptr->dml >> 3)) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else + state_ptr->ap += (-state_ptr->ap) >> 4; +} + +/* + * tandem_adjust(sr, se, y, i, sign) + * + * At the end of ADPCM decoding, it simulates an encoder which may be receiving + * the output of this decoder as a tandem process. If the output of the + * simulated encoder differs from the input to this decoder, the decoder output + * is adjusted by one level of A-law or u-law codes. + * + * Input: + * sr decoder output linear PCM sample, + * se predictor estimate sample, + * y quantizer step size, + * i decoder input code, + * sign sign bit of code i + * + * Return: + * adjusted A-law or u-law compressed sample. + */ +int +tandem_adjust_alaw( + int sr, /* decoder output linear PCM sample */ + int se, /* predictor estimate sample */ + int y, /* quantizer step size */ + int i, /* decoder input code */ + int sign, + short *qtab) +{ + unsigned char sp; /* A-law compressed 8-bit code */ + short dx; /* prediction error */ + char id; /* quantized prediction error */ + int sd; /* adjusted A-law decoded sample value */ + int im; /* biased magnitude of i */ + int imx; /* biased magnitude of id */ + + if (sr <= -32768) + sr = -1; + sp = linear2alaw((sr >> 1) << 3); /* short to A-law compression */ + dx = (alaw2linear(sp) >> 2) - se; /* 16-bit prediction error */ + id = quantize(dx, y, qtab, sign - 1); + + if (id == i) { /* no adjustment on sp */ + return (sp); + } else { /* sp adjustment needed */ + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + im = i ^ sign; /* 2's complement to biased unsigned */ + imx = id ^ sign; + + if (imx > im) { /* sp adjusted to next lower value */ + if (sp & 0x80) { + sd = (sp == 0xD5) ? 0x55 : + ((sp ^ 0x55) - 1) ^ 0x55; + } else { + sd = (sp == 0x2A) ? 0x2A : + ((sp ^ 0x55) + 1) ^ 0x55; + } + } else { /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0xAA) ? 0xAA : + ((sp ^ 0x55) + 1) ^ 0x55; + else + sd = (sp == 0x55) ? 0xD5 : + ((sp ^ 0x55) - 1) ^ 0x55; + } + return (sd); + } +} + +int +tandem_adjust_ulaw( + int sr, /* decoder output linear PCM sample */ + int se, /* predictor estimate sample */ + int y, /* quantizer step size */ + int i, /* decoder input code */ + int sign, + short *qtab) +{ + unsigned char sp; /* u-law compressed 8-bit code */ + short dx; /* prediction error */ + char id; /* quantized prediction error */ + int sd; /* adjusted u-law decoded sample value */ + int im; /* biased magnitude of i */ + int imx; /* biased magnitude of id */ + + if (sr <= -32768) + sr = 0; + sp = linear2ulaw(sr << 2); /* short to u-law compression */ + dx = (ulaw2linear(sp) >> 2) - se; /* 16-bit prediction error */ + id = quantize(dx, y, qtab, sign - 1); + if (id == i) { + return (sp); + } else { + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + im = i ^ sign; /* 2's complement to biased unsigned */ + imx = id ^ sign; + if (imx > im) { /* sp adjusted to next lower value */ + if (sp & 0x80) + sd = (sp == 0xFF) ? 0x7E : sp + 1; + else + sd = (sp == 0) ? 0 : sp - 1; + + } else { /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0x80) ? 0x80 : sp - 1; + else + sd = (sp == 0x7F) ? 0xFE : sp + 1; + } + return (sd); + } +} diff --git a/utils/wxMMedia/adpcm/g72x.h b/utils/wxMMedia/adpcm/g72x.h new file mode 100644 index 0000000000..dbfd64fd5b --- /dev/null +++ b/utils/wxMMedia/adpcm/g72x.h @@ -0,0 +1,123 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g72x.h + * + * Header file for CCITT conversion routines. + * + */ +#ifndef _G72X_H +#define _G72X_H + +#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */ +#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */ +#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */ + +/* + * The following is the definition of the state structure + * used by the G.721/G.723 encoder and decoder to preserve their internal + * state between successive calls. The meanings of the majority + * of the state structure fields are explained in detail in the + * CCITT Recommendation G.721. The field names are essentially indentical + * to variable names in the bit level description of the coding algorithm + * included in this Recommendation. + */ +struct g72x_state { + long yl; /* Locked or steady state step size multiplier. */ + short yu; /* Unlocked or non-steady state step size multiplier. */ + short dms; /* Short term energy estimate. */ + short dml; /* Long term energy estimate. */ + short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */ + + short a[2]; /* Coefficients of pole portion of prediction filter. */ + short b[6]; /* Coefficients of zero portion of prediction filter. */ + short pk[2]; /* + * Signs of previous two samples of a partially + * reconstructed signal. + */ + short dq[6]; /* + * Previous 6 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + short sr[2]; /* + * Previous 2 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + char td; /* delayed tone detect, new in 1988 version */ +}; + +/* External function definitions. */ + +extern unsigned char linear2alaw (int pcm_val); /* 2's complement (16-bit range) */ +extern int alaw2linear (unsigned char a_val); +extern unsigned char linear2ulaw (int pcm_val); /* 2's complement (16-bit range) */ +extern int ulaw2linear (unsigned char u_val); +extern int predictor_zero (struct g72x_state *state_ptr); +extern int predictor_pole (struct g72x_state *state_ptr); +extern int step_size (struct g72x_state *state_ptr); +extern int quantize (int d, int y, short *table, int size); +extern int reconstruct (int sign, int dqln, int y); + +extern void update + ( int code_size, int y, int wi, int fi, int dq + , int sr, int dqsez, struct g72x_state *state_ptr); + +int tandem_adjust_alaw + (int sr, int se, int y, int i, int sign, short *qtab); + +int tandem_adjust_ulaw + (int sr, int se, int y, int i, int sign, short *qtab); + +extern void g72x_init_state (struct g72x_state *); +extern int g721_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g721_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); +extern int g723_24_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g723_24_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); +extern int g723_40_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g723_40_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); + +#endif /* !_G72X_H */ diff --git a/utils/wxMMedia/cdbase.cpp b/utils/wxMMedia/cdbase.cpp new file mode 100644 index 0000000000..ea988372d7 --- /dev/null +++ b/utils/wxMMedia/cdbase.cpp @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndsnd.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation +#endif +#include "cdbase.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxCDtime wxCDAudio::CDtoc::GetTrackTime(wxUint8 track) const +{ + if (track > total_time.track) { + wxCDtime dummy_time = {0, 0, 0, 0}; + return dummy_time; + } + return tracks_time[track]; +} + +wxCDtime wxCDAudio::CDtoc::GetTrackPos(wxUint8 track) const +{ + if (track > total_time.track) { + wxCDtime dummy_time = {0, 0, 0, 0}; + return dummy_time; + } + return tracks_pos[track]; +} + +bool wxCDAudio::Play(const wxCDtime& beg_play) +{ + return Play(beg_play, GetToc().GetTotalTime()); +} + +bool wxCDAudio::Play(wxUint8 beg_track, wxUint8 end_track) +{ + wxCDtime beg_play = GetToc().GetTrackPos(beg_track); + wxCDtime end_play; + + if (end_track) + end_play = GetToc().GetTrackPos(end_track); + else + end_play = GetToc().GetTotalTime(); + return Play(beg_play, end_play); +} diff --git a/utils/wxMMedia/cdbase.h b/utils/wxMMedia/cdbase.h new file mode 100644 index 0000000000..1c254b0f12 --- /dev/null +++ b/utils/wxMMedia/cdbase.h @@ -0,0 +1,88 @@ +// -*- c++ -*- +// ///////////////////////////////////////////////////////////////////////////// +// Name: cdbase.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __CDA_base_H__ +#define __CDA_base_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "mmtype.h" + +typedef struct wxCDtime { + wxUint8 track; + wxUint8 hour, min, sec; +} wxCDtime; + +/// +class WXDLLEXPORT wxCDAudio : public wxObject { + DECLARE_ABSTRACT_CLASS(wxCDAudio) +public: + /// + typedef enum { PLAYING, PAUSED, STOPPED } CDstatus; + /// Table of contents manager + class CDtoc { + protected: + wxCDtime *tracks_time, *tracks_pos; + wxCDtime total_time; + public: + /// + CDtoc(wxCDtime& tot_tm, wxCDtime *trks_tm, wxCDtime *trks_pos) + { tracks_time = trks_tm; total_time = tot_tm; tracks_pos = trks_pos; } + + /// Returns the length of the specified track + /** @param track track to get length */ + wxCDtime GetTrackTime(wxUint8 track) const; + /** Returns the position of the specified + @param track track to get position */ + wxCDtime GetTrackPos(wxUint8 track) const; + /// Returns the total time + inline wxCDtime GetTotalTime() const { return total_time; } + }; +public: + /// + wxCDAudio() : wxObject() {} + /// + virtual ~wxCDAudio() {} + + /// Play audio at the specified position + /** + * @param beg_play start position + * @param end_play end position + */ + virtual bool Play(const wxCDtime& beg_play, const wxCDtime& end_play) = 0; + /// Play audio from the specified to the end of the CD audio + /** + * @param beg_play start position + */ + bool Play(const wxCDtime& beg_play); + /// + bool Play(wxUint8 beg_track, wxUint8 end_track = 0); + /// Pause the audio playing + virtual bool Pause() = 0; + /// Resume a paused audio playing + virtual bool Resume() = 0; + /// Get the current CD status + virtual CDstatus GetStatus() = 0; + /// Get the current playing time + virtual wxCDtime GetTime() = 0; + /// Returns the table of contents + virtual const CDtoc& GetToc() = 0; + /// CD ok + virtual bool Ok() const = 0; +}; + +#endif diff --git a/utils/wxMMedia/cdunix.cpp b/utils/wxMMedia/cdunix.cpp new file mode 100644 index 0000000000..07f5ea0598 --- /dev/null +++ b/utils/wxMMedia/cdunix.cpp @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: cdlinux.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "cdunix.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#else +// For Solaris +#include +#endif + +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "mmtype.h" +#include "cdunix.h" + +wxCDAudioLinux::wxCDAudioLinux() + : wxCDAudio(), m_fd(-1) +{ + OpenDevice("/dev/cdrom"); +} + +wxCDAudioLinux::wxCDAudioLinux(const char *dev_name) + : wxCDAudio(), m_fd(-1) +{ + OpenDevice(dev_name); +} + +wxCDAudioLinux::~wxCDAudioLinux() +{ + if (m_fd != -1) { + close(m_fd); + wxDELETE(m_trksize); + wxDELETE(m_trkpos); + } +} + +void wxCDAudioLinux::OpenDevice(const char *dev_name) +{ + struct cdrom_tocentry entry, old_entry; + struct cdrom_tochdr diskinf; + struct cdrom_msf0 *msf = &entry.cdte_addr.msf, + *old_msf = &old_entry.cdte_addr.msf; + wxCDtime *the_track; + wxCDtime tot_tm; + wxUint8 nb_tracks, i; + int hour, minute, second; + + if (m_fd != -1) + return; + + m_fd = open(dev_name, O_RDONLY); + if (m_fd == -1) { + m_toc = NULL; + return; + } + m_status = STOPPED; + + ioctl(m_fd, CDROMREADTOCHDR, &diskinf); + + nb_tracks = diskinf.cdth_trk1-diskinf.cdth_trk0+1; + m_trksize = new wxCDtime[nb_tracks+1]; + m_trkpos = new wxCDtime[nb_tracks+1]; + + old_msf->minute = 0; + old_msf->second = 0; + for (i=diskinf.cdth_trk0;i<=diskinf.cdth_trk1;i++) { + entry.cdte_track = i; + entry.cdte_format = CDROM_MSF; + ioctl(m_fd, CDROMREADTOCENTRY, &entry); + + minute = msf->minute - old_msf->minute; + second = msf->second - old_msf->second; + if (second < 0) { + minute--; + second += 60; + } + + hour = minute / 60; + minute %= 60; + + the_track = &m_trksize[i-diskinf.cdth_trk0]; + the_track->track = i-diskinf.cdth_trk0; + the_track->hour = hour; + the_track->min = minute; + the_track->sec = second; + + the_track = &m_trkpos[i-diskinf.cdth_trk0]; + the_track->track = i-diskinf.cdth_trk0; + the_track->hour = old_msf->minute / 60; + the_track->min = old_msf->minute % 60; + the_track->sec = old_msf->second; + old_entry = entry; + } + + entry.cdte_track = CDROM_LEADOUT; + entry.cdte_format = CDROM_MSF; + ioctl(m_fd, CDROMREADTOCENTRY, &entry); + + tot_tm.track = nb_tracks; + tot_tm.hour = msf->minute / 60; + tot_tm.min = msf->minute % 60; + tot_tm.sec = msf->second % 60; + + m_trksize[nb_tracks].track = nb_tracks; + minute = msf->minute - old_msf->minute; + second = msf->second - old_msf->second; + if (second < 0) { + minute--; + second += 60; + } + hour = minute / 60; + minute %= 60; + + m_trksize[nb_tracks].hour = hour; + m_trksize[nb_tracks].min = minute; + m_trksize[nb_tracks].sec = second; + m_trkpos[nb_tracks].track = nb_tracks; + m_trkpos[nb_tracks].hour = old_msf->minute / 60; + m_trkpos[nb_tracks].min = old_msf->minute % 60; + m_trkpos[nb_tracks].sec = old_msf->second; + + m_toc = new CDtoc(tot_tm, m_trksize, m_trkpos); +} + +bool wxCDAudioLinux::Play(const wxCDtime& beg_time, const wxCDtime& end_time) +{ + struct cdrom_msf track_msf; + + track_msf.cdmsf_min0 = beg_time.hour * 60 + beg_time.min; + track_msf.cdmsf_sec0 = beg_time.sec; + track_msf.cdmsf_frame0 = 0; + track_msf.cdmsf_min1 = end_time.hour * 60 + end_time.min; + track_msf.cdmsf_sec1 = end_time.sec; + track_msf.cdmsf_frame1 = 0; + return (ioctl(m_fd, CDROMPLAYMSF, &track_msf) != -1); +} + +bool wxCDAudioLinux::Pause() +{ + return (ioctl(m_fd, CDROMPAUSE, 0) != -1); +} + +bool wxCDAudioLinux::Resume() +{ + return (ioctl(m_fd, CDROMRESUME, 0) != -1); +} + +wxCDAudio::CDstatus wxCDAudioLinux::GetStatus() +{ + struct cdrom_subchnl subchnl; + ioctl(m_fd, CDROMSUBCHNL, &subchnl); + switch (subchnl.cdsc_audiostatus) { + case CDROM_AUDIO_PLAY: return PLAYING; + case CDROM_AUDIO_PAUSED: return PAUSED; + case CDROM_AUDIO_COMPLETED: return STOPPED; + } + + return STOPPED; +} + +wxCDtime wxCDAudioLinux::GetTime() +{ + wxCDtime cdtime; + struct cdrom_subchnl subchnl; + + ioctl(m_fd, CDROMSUBCHNL, &subchnl); + cdtime.track = subchnl.cdsc_trk; + cdtime.min = subchnl.cdsc_reladdr.msf.minute; + cdtime.hour = cdtime.min / 60; + cdtime.min %= 60; + cdtime.sec = subchnl.cdsc_reladdr.msf.second; + + return cdtime; +} + +wxCDAudio::CDtoc& wxCDAudioLinux::GetToc() +{ + return *m_toc; +} diff --git a/utils/wxMMedia/cdunix.h b/utils/wxMMedia/cdunix.h new file mode 100644 index 0000000000..0f8d73b324 --- /dev/null +++ b/utils/wxMMedia/cdunix.h @@ -0,0 +1,61 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: cdunix.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __CDUNIXH__ +#define __CDUNIXH__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "mmtype.h" +#include "cdbase.h" + +/// +class WXDLLEXPORT wxCDAudioLinux : public wxCDAudio { + DECLARE_DYNAMIC_CLASS(wxCDAudioLinux) +protected: + wxCDtime m_time; + CDstatus m_status; + CDtoc *m_toc; + int m_fd; + wxCDtime *m_trksize, *m_trkpos; +public: + /// + wxCDAudioLinux(); + /// + wxCDAudioLinux(const char *dev_name); + /// + virtual ~wxCDAudioLinux(); + + /// + virtual bool Play(const wxCDtime& beg_time, const wxCDtime& end_time); + /// + virtual bool Pause(); + /// + virtual bool Resume(); + /// + virtual CDstatus GetStatus(); + /// + virtual wxCDtime GetTime(); + /// + virtual CDtoc& GetToc(); + /// + virtual inline bool Ok() const { return (m_fd != -1); } +protected: + /// + void OpenDevice(const char *dev_name); +}; + +#endif diff --git a/utils/wxMMedia/cdwin.cpp b/utils/wxMMedia/cdwin.cpp new file mode 100644 index 0000000000..abe8469b70 --- /dev/null +++ b/utils/wxMMedia/cdwin.cpp @@ -0,0 +1,208 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: cdwin.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "cdwin.h" +#endif + +#include +#include +#include +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#define WXMMEDIA_INTERNAL +#include "mmtype.h" +#include "cdbase.h" +#include "cdwin.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxCDAudioWin::wxCDAudioWin(void) + : wxCDAudio(), m_trksize(NULL), m_trkpos(NULL), m_ok(TRUE), m_toc(NULL) +{ + MCI_OPEN_PARMS open_struct; + MCI_SET_PARMS set_struct; + DWORD ret; + + m_internal = new CDAW_Internal; + open_struct.lpstrDeviceType = "cdaudio"; + ret = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE, + (DWORD)&open_struct); + if (ret) { + m_ok = FALSE; + return; + } + m_internal->dev_id = open_struct.wDeviceID; + + set_struct.dwTimeFormat = MCI_FORMAT_MSF; + ret = mciSendCommand(m_internal->dev_id, MCI_SET, MCI_SET_TIME_FORMAT, + (DWORD)(LPVOID)&set_struct); + + PrepareToc(); + + set_struct.dwTimeFormat = MCI_FORMAT_TMSF; + ret = mciSendCommand(m_internal->dev_id, MCI_SET, MCI_SET_TIME_FORMAT, + (DWORD)(LPVOID)&set_struct); +} + +wxCDAudioWin::~wxCDAudioWin(void) +{ + if (m_ok) { + mciSendCommand(m_internal->dev_id, MCI_CLOSE, 0, NULL); + delete m_toc; + delete[] m_trksize; + delete[] m_trkpos; + } + delete m_internal; +} + +void wxCDAudioWin::PrepareToc(void) +{ + MCI_STATUS_PARMS status_struct; + MCI_SET_PARMS set_struct; + wxUint16 i, nb_m_trksize; + wxCDtime total_time, *trk; + DWORD ret, tmem; + + if (!m_ok) + return; + + status_struct.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + ret = mciSendCommand(m_internal->dev_id, MCI_STATUS, MCI_STATUS_ITEM, + (DWORD)&status_struct); + nb_m_trksize = status_struct.dwReturn; + + m_trksize = new wxCDtime[nb_m_trksize+1]; + m_trkpos = new wxCDtime[nb_m_trksize+1]; + + status_struct.dwItem = MCI_STATUS_LENGTH; + ret = mciSendCommand(m_internal->dev_id, MCI_STATUS, MCI_STATUS_ITEM, + (DWORD)&status_struct); + total_time.track = nb_m_trksize; + tmem = status_struct.dwReturn; + total_time.min = MCI_MSF_MINUTE(tmem); + total_time.sec = MCI_MSF_SECOND(tmem); + total_time.hour = total_time.min / 60; + total_time.min %= 60; + + for (i=1;i<=nb_m_trksize;i++) { + status_struct.dwItem = MCI_STATUS_POSITION; + status_struct.dwTrack = i; + ret = mciSendCommand(m_internal->dev_id, MCI_STATUS, + MCI_STATUS_ITEM | MCI_TRACK, + (DWORD)(LPVOID)&status_struct); + tmem = status_struct.dwReturn; + + trk = &m_trkpos[i]; + trk->track = i; + trk->min = MCI_MSF_MINUTE(tmem); + trk->sec = MCI_MSF_SECOND(tmem); + trk->hour = trk->min / 60; + trk->min %= 60; + + status_struct.dwItem = MCI_STATUS_LENGTH; + status_struct.dwTrack = i; + ret = mciSendCommand(m_internal->dev_id, MCI_STATUS, + MCI_STATUS_ITEM | MCI_TRACK, + (DWORD)(LPVOID)&status_struct); + tmem = status_struct.dwReturn; + + trk = &m_trksize[i]; + trk->track = i; + trk->min = MCI_MSF_MINUTE(tmem); + trk->sec = MCI_MSF_SECOND(tmem); + trk->hour = trk->min / 60; + trk->min %= 60; + } + + m_toc = new CDtoc(total_time, m_trksize, m_trkpos); +} + +bool wxCDAudioWin::Play(const wxCDtime& beg_time, const wxCDtime& end_time) +{ + DWORD tmsf; + MCI_PLAY_PARMS play_struct; + + if (!m_ok) + return FALSE; + + tmsf = MCI_MAKE_TMSF(beg_time.track, beg_time.min, + beg_time.sec, 0); + play_struct.dwFrom = tmsf; + tmsf = MCI_MAKE_TMSF(end_time.track, end_time.min, + end_time.sec, 0); + play_struct.dwTo = tmsf; + + mciSendCommand(m_internal->dev_id, MCI_PLAY, 0, (DWORD)&play_struct); + return TRUE; +} + +bool wxCDAudioWin::Pause(void) +{ + if (!m_ok) + return FALSE; + + return (mciSendCommand(m_internal->dev_id, MCI_PAUSE, 0, 0) == 0); +} + +bool wxCDAudioWin::Resume(void) +{ + if (!m_ok) + return FALSE; + + return (mciSendCommand(m_internal->dev_id, MCI_RESUME, 0, 0) == 0); +} + +wxCDAudio::CDstatus wxCDAudioWin::GetStatus(void) +{ + MCI_STATUS_PARMS status_struct; + + if (!m_ok) + return STOPPED; + + status_struct.dwItem = MCI_STATUS_MODE; + mciSendCommand(m_internal->dev_id, MCI_STATUS, MCI_STATUS_ITEM, + (DWORD)&status_struct); + switch (status_struct.dwReturn) { + case MCI_MODE_PAUSE: + return PAUSED; + case MCI_MODE_PLAY: + return PLAYING; + } + return STOPPED; +} + +wxCDtime wxCDAudioWin::GetTime(void) +{ + MCI_STATUS_PARMS status_struct; + wxCDtime cd_time = {-1, -1, -1, -1}; + + if (!m_ok) + return cd_time; + + status_struct.dwItem = MCI_STATUS_TIME_FORMAT; + mciSendCommand(m_internal->dev_id, MCI_STATUS, MCI_STATUS_ITEM, + (DWORD)&status_struct); + cd_time.track = MCI_TMSF_TRACK(status_struct.dwReturn); + cd_time.min = MCI_TMSF_MINUTE(status_struct.dwReturn); + cd_time.sec = MCI_TMSF_SECOND(status_struct.dwReturn); + cd_time.hour = cd_time.min / 60; + cd_time.min %= 60; + return cd_time; +} + +wxCDAudio::CDtoc& wxCDAudioWin::GetToc(void) +{ + return *m_toc; +} diff --git a/utils/wxMMedia/cdwin.h b/utils/wxMMedia/cdwin.h new file mode 100644 index 0000000000..21db70ea9c --- /dev/null +++ b/utils/wxMMedia/cdwin.h @@ -0,0 +1,67 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: cdwin.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __CDA_win_H__ +#define __CDA_win_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "mmtype.h" +#include "cdbase.h" + +#ifdef WXMMEDIA_INTERNAL +#include +#include +typedef struct CDAW_Internal { + MCIDEVICEID dev_id; +} CDAW_Internal; +#endif + +/// +class WXDLLEXPORT wxCDAudioWin : public wxCDAudio { + DECLARE_DYNAMIC_CLASS(wxCDAudioWin) +protected: + struct CDAW_Internal *m_internal; + wxCDtime *m_trksize, *m_trkpos; + CDtoc *m_toc; + bool m_ok; +public: + /// + wxCDAudioWin(void); + /// + wxCDAudioWin(const char *dev_name); + /// + virtual ~wxCDAudioWin(void); + + /// + virtual bool Play(const wxCDtime& beg_time, const wxCDtime& end_time); + /// + virtual bool Pause(void); + /// + virtual bool Resume(void); + /// + virtual CDstatus GetStatus(void); + /// + virtual wxCDtime GetTime(void); + /// + virtual CDtoc& GetToc(void); + /// + virtual inline bool Ok(void) const { return m_ok; } +protected: + void PrepareToc(); +}; + +#endif diff --git a/utils/wxMMedia/mmdata.cpp b/utils/wxMMedia/mmdata.cpp new file mode 100644 index 0000000000..11b0922cf6 --- /dev/null +++ b/utils/wxMMedia/mmdata.cpp @@ -0,0 +1,92 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: mmdata.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#include "mmfile.h" + +#include "sndsnd.h" +#include "sndfrmt.h" +#if defined(__UNIX__) +#include "snduss.h" +#endif +#include "sndfrag.h" +#include "sndfile.h" +#include "sndwav.h" +#include "sndaiff.h" +#include "sndau.h" +#include "sndpcm.h" +#include "sndmulaw.h" +#include "vidbase.h" +#if defined(__X__) || defined(__WXGTK__) +#include "vidxanm.h" +#endif +#ifdef __WINDOWS__ +#include "sndwin.h" +#include "cdwin.h" +#include "vidwin.h" +#endif +#include "cdbase.h" +#ifdef __UNIX__ +#include "cdunix.h" +#endif +#include "mmsolve.h" +// #include "midfile.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxSound, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxSndBuffer, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxSndSimpleBuffer, wxSndBuffer) + +IMPLEMENT_ABSTRACT_CLASS(wxSoundCodec, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxSoundPcmCodec, wxSoundCodec) +IMPLEMENT_DYNAMIC_CLASS(wxSoundMulawCodec, wxSoundCodec) + +#ifdef __UNIX__ +IMPLEMENT_DYNAMIC_CLASS(wxUssSound, wxSound) +#endif +#ifdef __WINDOWS__ +IMPLEMENT_DYNAMIC_CLASS(wxWinSound, wxSound) +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxSndFileCodec, wxMMediaFile) +IMPLEMENT_DYNAMIC_CLASS(wxSndWavCodec, wxSndFileCodec) +IMPLEMENT_DYNAMIC_CLASS(wxSndAuCodec, wxSndFileCodec) +IMPLEMENT_DYNAMIC_CLASS(wxSndAiffCodec, wxSndFileCodec) + +IMPLEMENT_ABSTRACT_CLASS(wxVideoBaseDriver, wxMMediaFile) +IMPLEMENT_DYNAMIC_CLASS(wxVideoOutput, wxWindow) +#if defined(__X__) || defined(__WXGTK__) +IMPLEMENT_DYNAMIC_CLASS(wxVideoXANIM, wxVideoBaseDriver) +#endif +#ifdef __WINDOWS__ +IMPLEMENT_DYNAMIC_CLASS(wxVideoWindows, wxVideoBaseDriver) +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxCDAudio, wxObject) +#ifdef linux +IMPLEMENT_DYNAMIC_CLASS(wxCDAudioLinux, wxCDAudio) +#else +IMPLEMENT_DYNAMIC_CLASS(wxCDAudioWin, wxCDAudio) +#endif + +// IMPLEMENT_ABSTRACT_CLASS(wxMidiFile, wxObject) + +wxMediaFileSolve::wxMFileList *wxMediaFileSolve::m_first = NULL; +wxUint8 wxMediaFileSolve::m_devnum = 0; + +MMD_REGISTER_FILE("audio/x-wav", "Wav Player", wxSndWavCodec, "wav") +MMD_REGISTER_FILE("audio/x-aiff", "Aiff Player", wxSndAiffCodec, "aif") +MMD_REGISTER_FILE("audio/x-au", "Sun Audio File Player", wxSndAuCodec, "au") +#if defined(__X__) || defined(__WXGTK__) +MMD_REGISTER_FILE("video/*", "Video Player", wxVideoXANIM, "mov") +#else +MMD_REGISTER_FILE("video/avi", "AVI Player", wxVideoWindows, "avi") +#endif diff --git a/utils/wxMMedia/mmedia.h b/utils/wxMMedia/mmedia.h new file mode 100644 index 0000000000..a530b7bc36 --- /dev/null +++ b/utils/wxMMedia/mmedia.h @@ -0,0 +1,31 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: mmedia.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __MMEDIA_H__ +#define __MMEDIA_H__ + +#ifdef __WINDOWS__ + +#include "sndwin.h" +#define wxSoundDevice wxWinSound + +#include "vidwin.h" +#define wxVideoDevice wxVideoWindows + +#else + +#include "snduss.h" +#define wxSoundDevice wxUssSound + +#include "vidxanm.h" +#define wxVideoDevice wxVideoXANIM + +#endif + +#endif diff --git a/utils/wxMMedia/mmfile.cpp b/utils/wxMMedia/mmfile.cpp new file mode 100644 index 0000000000..fa57adfc7f --- /dev/null +++ b/utils/wxMMedia/mmfile.cpp @@ -0,0 +1,194 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: mmfile.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation +#endif +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include +#include +#include + +#include "mmfile.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxMMediaFile::wxMMediaFile() + : m_istream(NULL), m_i_temp(NULL), m_ostream(NULL), m_o_temp(NULL), + m_tmpfname((char *)NULL), m_mfname((char *)NULL), + m_seekable(FALSE) +{ +} + +wxMMediaFile::wxMMediaFile(wxOutputStream& os, bool seekable) + : m_istream(NULL), m_i_temp(NULL), m_ostream(&os), m_o_temp(NULL), + m_tmpfname((char *)NULL), m_mfname((char *)NULL), + m_seekable(seekable) +{ +} + +wxMMediaFile::wxMMediaFile(wxInputStream& is, bool preload, bool seekable) + : m_istream(&is), m_i_temp(NULL), m_ostream(NULL), m_o_temp(NULL), + m_tmpfname((char *)NULL), m_mfname((char *)NULL), + m_seekable(seekable) +{ +/* + if (preload) { + wxMemoryStream *tmpstream = new wxMemoryStream(); + + m_o_temp = tmpstream; + m_i_temp = tmpstream; + + m_o_temp->Write(is); + } +*/ +} + +wxMMediaFile::wxMMediaFile(const wxString& fname) + : m_istream(NULL), m_i_temp(NULL), m_ostream(NULL), m_o_temp(NULL), + m_tmpfname((char *)NULL), m_mfname(fname), + m_seekable(TRUE) +{ + wxFileStream *s = new wxFileStream(fname); + + m_mfname = fname; + m_istream = s; + m_ostream = s; +} + +void wxMMediaFile::SetFile(wxInputStream& str, bool preload, bool seekable) +{ + CleanUpPrevious(); + m_istream = &str; + m_ostream = NULL; + m_seekable = seekable; + +/* + if (preload) { + wxMemoryStream *tmpstream = new wxMemoryStream(); + + m_i_temp = tmpstream; + m_o_temp = tmpstream; + + m_o_temp->Write(str); + } +*/ +} + +void wxMMediaFile::SetFile(wxOutputStream& str, bool seekable) +{ + CleanUpPrevious(); + m_ostream = &str; + m_istream = NULL; + m_seekable = seekable; +} + +void wxMMediaFile::SetFile(const wxString& fname) +{ + CleanUpPrevious(); + + m_mfname = fname; + wxFileStream *f = new wxFileStream(fname); + + SetFile(*f, FALSE, TRUE); +} + +void wxMMediaFile::CleanUpPrevious() +{ + if (m_i_temp) { + m_i_temp->SeekI(0); + + if (m_ostream) + m_ostream->Write(*m_i_temp); + + delete m_i_temp; // Only one delete because m_tmpo* and m_tmpi* are linked + + if (m_tmpfname) + wxRemoveFile(m_tmpfname); + } + + if (!m_mfname.IsNull() && m_mfname != "") + delete m_istream; + + m_i_temp = NULL; + m_o_temp = NULL; + m_istream = NULL; + m_ostream = NULL; +} + +wxMMediaFile::~wxMMediaFile() +{ + CleanUpPrevious(); +} + +wxMMtime wxMMediaFile::GetLength() +{ + wxMMtime mm_time = {-1, 0, 0}; + return mm_time; +} + +wxMMtime wxMMediaFile::GetPosition() +{ + wxMMtime mm_time = {0, 0, 0}; + return mm_time; +} + +wxInputStream *wxMMediaFile::GetIRawData() +{ + if (!m_istream) + return NULL; + + if (!m_seekable && !m_i_temp) + CacheIO(); + + return (m_i_temp) ? m_i_temp : m_istream; +} + +wxOutputStream *wxMMediaFile::GetORawData() +{ + if (!m_ostream) + return NULL; + + if (!m_seekable && !m_i_temp) + CacheIO(); + + return (m_o_temp) ? m_o_temp : m_ostream; +} + +wxString wxMMediaFile::GetCurrentFile() +{ + if (!m_istream && !m_ostream) + return wxString((char *)NULL); + + if (!m_mfname && !m_i_temp) + CacheIO(); + + return (!m_tmpfname.IsEmpty()) ? m_tmpfname : m_mfname; +} + +void wxMMediaFile::CacheIO() +{ + if ((!m_istream && !m_ostream) || m_i_temp) + return; + + m_tmpfname = wxGetTempFileName("mmd"); + + wxFileStream *tmpstream = new wxFileStream(m_tmpfname); + m_i_temp = tmpstream; + m_o_temp = tmpstream; + + if (m_istream) + tmpstream->wxOutputStream::Write(*m_istream); +} diff --git a/utils/wxMMedia/mmfile.h b/utils/wxMMedia/mmfile.h new file mode 100644 index 0000000000..29b3968821 --- /dev/null +++ b/utils/wxMMedia/mmfile.h @@ -0,0 +1,94 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: mmfile.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __MMD_file_H__ +#define __MMD_file_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "wx/string.h" +#include "wx/stream.h" +#include "mmtype.h" + +/// +typedef enum { + wxMMFILE_NOERROR, + wxMMFILE_INVALID, + wxMMFILE_EOF +} /// + wxMMFileError; + +typedef struct { + wxInt8 hours; + wxUint8 minutes, seconds; +} wxMMtime; + +/// Common base class for multimedia file. +class wxMMediaFile { +public: + wxMMediaFile(); + /// + wxMMediaFile(wxInputStream& is, bool preload, bool seekable); + /// + wxMMediaFile(wxOutputStream& is, bool seekable); + /// + wxMMediaFile(const wxString& fname); + /// + virtual ~wxMMediaFile(); + + /// + wxInputStream *GetIRawData(); + wxOutputStream *GetORawData(); + /// + wxString GetCurrentFile(); + + /// + virtual void SetFile(wxInputStream& is, + bool preload = FALSE, bool seekable = FALSE); + /// + virtual void SetFile(wxOutputStream& is, bool seekable = FALSE); + /// + void SetFile(const wxString& fname); + + /// + wxMMFileError GetFileError() const { return m_mmerror; } + /// + virtual wxMMtime GetLength(); + /// + virtual wxMMtime GetPosition(); + /// + virtual bool StartPlay() = 0; + /// + virtual void StopPlay() = 0; +protected: + /// + wxMMFileError m_mmerror; + /// + wxInputStream *m_istream, *m_i_temp; + /// + wxOutputStream *m_ostream, *m_o_temp; + /// + wxString m_tmpfname, m_mfname; + /// + bool m_seekable; + + /// + void CacheIO(); + /// + void CleanUpPrevious(); +}; + +#endif diff --git a/utils/wxMMedia/mmriff.cpp b/utils/wxMMedia/mmriff.cpp new file mode 100644 index 0000000000..10c8188195 --- /dev/null +++ b/utils/wxMMedia/mmriff.cpp @@ -0,0 +1,215 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: mmriff.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "mmriff.h" +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "mmfile.h" +#include "mmriff.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxRiffCodec::wxRiffCodec() : + riff_i_stream(NULL), riff_o_stream(NULL), chunk_length(INVALID_CHUNK_LEN) +{ +} + +wxRiffCodec::wxRiffCodec(wxInputStream& s) : + riff_i_stream(&s), riff_o_stream(NULL), chunk_length(INVALID_CHUNK_LEN) +{ +} + +wxRiffCodec::wxRiffCodec(wxOutputStream& s) : + riff_i_stream(NULL), riff_o_stream(&s), chunk_length(INVALID_CHUNK_LEN) +{ +} + +wxRiffCodec::~wxRiffCodec() +{ +} + +bool wxRiffCodec::RiffReset(wxUint8 mode) +{ + switch (mode) { + case RIFF_READ: + if (!riff_i_stream) + return FALSE; + riff_i_stream->SeekI(0); + chunk_length = INVALID_CHUNK_LEN; + return TRUE; + case RIFF_WRITE: + if (!riff_o_stream) + return FALSE; + riff_o_stream->SeekO(0); + chunk_length = INVALID_CHUNK_LEN; + return TRUE; + } + return FALSE; +} + +bool wxRiffCodec::ReadData(void *data, wxUint32 size) +{ + if (!riff_i_stream) + return FALSE; + + if (chunk_length != INVALID_CHUNK_LEN && (wxUint32)chunk_length < size) { + riff_error = wxMMFILE_EOF; + return FALSE; + } + if (chunk_length != INVALID_CHUNK_LEN) + chunk_length -= size; + + bool ret = (riff_i_stream->Read((char *)data, size).LastRead() == size); + + return ret; +} + +bool wxRiffCodec::WriteData(void *data, wxUint32 size) +{ + if (!riff_o_stream) + return FALSE; + + if (chunk_length < size) { + riff_error = wxMMFILE_EOF; + return FALSE; + } + chunk_length -= size; + + riff_o_stream->Write(data, size); + + return TRUE; +} + +bool wxRiffCodec::Read32(wxUint32& i32) +{ + wxUint8 i8[4]; + + if (!ReadData(i8, 4)) + return FALSE; + + i32 = i8[0]; + i32 |= ((wxUint32)i8[1]) << 8; + i32 |= ((wxUint32)i8[2]) << 16; + i32 |= ((wxUint32)i8[3]) << 24; + + return TRUE; +} + +bool wxRiffCodec::Write32(wxUint32 i32) +{ + wxUint8 i8[4]; + + i8[0] = i32 & 0xff; + i8[1] = (i32 >> 8) & 0xff; + i8[2] = (i32 >> 16) & 0xff; + i8[3] = (i32 >> 24) & 0xff; + + if (!WriteData(i8, 4)) + return FALSE; + + return TRUE; +} + +bool wxRiffCodec::Read16(wxUint16& i16) +{ + wxUint8 i8[2]; + + if (!ReadData(i8, 2)) + return FALSE; + + i16 = i8[0]; + i16 |= ((wxUint16)i8[1]) << 8; + + return TRUE; +} + +bool wxRiffCodec::Write16(wxUint16 i16) +{ + wxUint8 i8[2]; + + i8[0] = i16 & 0xff; + i8[1] = (i16 >> 8) & 0xff; + + if (!WriteData(i8, 2)) + return FALSE; + + return TRUE; +} + +bool wxRiffCodec::Skip(wxUint32 skip) +{ + if (!riff_i_stream || (chunk_length != INVALID_CHUNK_LEN && (wxInt32)skip > chunk_length)) + return FALSE; + + if (chunk_length != INVALID_CHUNK_LEN) + chunk_length -= skip; + riff_i_stream->SeekI(skip, wxFromCurrent); + + return TRUE; +} + +bool wxRiffCodec::CreateChunk(const wxString& name, wxUint32 size) +{ + if (!riff_o_stream || name.Length() != 4) + return FALSE; + + if (riff_o_stream->Write(name.GetData(), 4).LastError()) { + riff_error = wxMMFILE_EOF; + return FALSE; + } + + chunk_length = size+4; + + return Write32(size); +} + +bool wxRiffCodec::FindChunk(const wxString& name, bool from_here) +{ + char buf[5]; + wxString str2; + + if (!riff_i_stream) + return FALSE; + + if (chunk_length != INVALID_CHUNK_LEN && !from_here) + Skip(chunk_length); + while (1) { + if (riff_i_stream->Read(buf, 4).LastError()) { + riff_error = wxMMFILE_EOF; + return FALSE; + } + + chunk_length = INVALID_CHUNK_LEN; + if (!Read32(chunk_length)) { + riff_error = wxMMFILE_EOF; + return FALSE; + } + + buf[4] = 0; + str2 = buf; + if ((!name.IsNull()) && str2 != name) { + Skip(chunk_length); + continue; + } + + m_chunk = str2; + + return TRUE; + } + + return TRUE; +} diff --git a/utils/wxMMedia/mmriff.h b/utils/wxMMedia/mmriff.h new file mode 100644 index 0000000000..5ea5395277 --- /dev/null +++ b/utils/wxMMedia/mmriff.h @@ -0,0 +1,81 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: mmriff.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1998 +// Updated: +// Copyright: (C) 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __MM_riff_H__ +#define __MM_riff_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmtype.h" +#include "mmfile.h" + +#define RIFF_READ 0 +#define RIFF_WRITE 1 +#define INVALID_CHUNK_LEN ((wxUint32)-1) + +/// +class wxRiffCodec { +public: + /// + wxRiffCodec(); + /// + wxRiffCodec(wxOutputStream& s); + /// + wxRiffCodec(wxInputStream& s); + /// + virtual ~wxRiffCodec(); + + /// + void SetFile(wxInputStream& s) { cout << "RIFF:SetFile(i)" << endl; riff_i_stream = &s; riff_o_stream = NULL; } + /// + void SetFile(wxOutputStream& s) { cout << "RIFF::SetFile(o)" << endl; riff_i_stream = NULL; riff_o_stream = &s; } + + /// + bool Read32(wxUint32& i32); + /// + bool Read16(wxUint16& i16); + /// + bool ReadData(void *data, wxUint32 size); + /// + bool Skip(wxUint32 skip); + + /// + bool Write32(wxUint32 i32); + /// + bool Write16(wxUint16 i16); + /// + bool WriteData(void *data, wxUint32 size); + + /// + inline wxUint32 GetChunkLength() const { return chunk_length; } + /// + inline const wxString& GetChunkName() const { return m_chunk; } + + /// + bool RiffReset(wxUint8 state); + + /// + bool FindChunk(const wxString& name = "", bool from_here = FALSE); + /// + bool CreateChunk(const wxString& name, wxUint32 chunk_size); + + /// + inline wxMMFileError GetError() const { return riff_error; } + +protected: + wxInputStream *riff_i_stream; + wxOutputStream *riff_o_stream; + wxUint32 chunk_length; + wxMMFileError riff_error; + wxString m_chunk; +}; + +#endif diff --git a/utils/wxMMedia/mmsolve.cpp b/utils/wxMMedia/mmsolve.cpp new file mode 100644 index 0000000000..fd4fef2f03 --- /dev/null +++ b/utils/wxMMedia/mmsolve.cpp @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: mmsolve.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation +#endif +#include "mmsolve.h" + +wxMMediaFile *wxMediaFileSolve::ByExtension(const wxString& filename) +{ + wxMFileList *list = m_first; + wxString tmp, f_ext; + int pos = filename.Find('.', TRUE)+1; + + tmp = filename; + f_ext = tmp(pos, filename.Length()-pos); + + printf("f_ext = %s\n", f_ext.GetData()); + while (list) { + printf("list->ext = %s\n", list->ext.GetData()); + if (list->ext.CompareTo(f_ext) == 0) { + wxMMediaFile *mmf = list->creator(); + return mmf; + } + list = list->next; + } + return NULL; +} + +wxMMediaFile *wxMediaFileSolve::ByName(const wxString& name) +{ + wxMFileList *list = m_first; + + while (list) { + if (list->name == name) + return (wxMMediaFile *)(list->creator()); + list = list->next; + } + return NULL; +} + +bool wxMatchMimeType(const wxString& mime_obj, const wxString& type) +{ +#ifdef USE_GNU_WXSTRING + wxString mime2_obj = mime_obj; + wxString type2 = type; +#define mime_obj mime2_obj +#define type type2 +#endif + + if (mime_obj.Find('*') != -1) { + wxString part_str1[2], part_str2[2]; + + part_str1[0] = mime_obj.Left('/'); + part_str1[1] = mime_obj.After('/'); + + part_str2[0] = type.Left('/'); + part_str2[1] = type.After('/'); + + if (part_str1[0] == "*" && part_str1[1] == "*") + return TRUE; + + if (part_str1[0] == "*" && part_str1[1] == part_str2[1]) + return TRUE; + + if (part_str1[1] == "*" && part_str1[0] == part_str2[1]) + return TRUE; + + return FALSE; + } + if (mime_obj == type) + return TRUE; + return FALSE; +} + +wxMMediaFile *wxMediaFileSolve::ByType(const wxString& type) +{ + wxMFileList *list = m_first; + + while (list) { + if (wxMatchMimeType(*(list->mime_type), type)) + return (wxMMediaFile *)(list->creator()); + list = list->next; + } + return NULL; +} + +void wxMediaFileSolve::ListMDevice(wxString*& names, wxUint8& devices) +{ + wxMFileList *list = m_first; + wxUint8 d = 0; + + if (!m_devnum) { + names = NULL; + return; + } + devices = m_devnum; + names = new wxString[devices]; + + while (list) { + names[d++] = list->name; + list = list->next; + } +} + +wxMMDfileRegister::wxMMDfileRegister(wxMediaFileCreator cbk, + char *mtype, char *ext, char *name) +{ + wxMediaFileSolve::wxMFileList *entry = new wxMediaFileSolve::wxMFileList; + + entry->next = wxMediaFileSolve::m_first; + entry->creator = cbk; + entry->mime_type = wxString(mtype); + entry->name = wxString(name); + entry->ext = wxString(ext); + wxMediaFileSolve::m_devnum++; + wxMediaFileSolve::m_first = entry; +} diff --git a/utils/wxMMedia/mmsolve.h b/utils/wxMMedia/mmsolve.h new file mode 100644 index 0000000000..04ef8f8080 --- /dev/null +++ b/utils/wxMMedia/mmsolve.h @@ -0,0 +1,92 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: mmsolve.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __MMD_solve_H__ +#define __MMD_solve_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "mmfile.h" + +/** @name Solver classes */ +//@{ + +typedef wxMMediaFile *(*wxMediaFileCreator)(); + +/** wxMediaFileSolve is a class to do name resolution on multimedia files + * @memo Multimedia file solver + * @author Guilhem Lavaux + */ +class WXDLLEXPORT wxMediaFileSolve : public wxObject { +protected: + typedef struct wxMFileList { + wxMediaFileCreator creator; + wxString mime_type, name, ext; + wxMFileList *next; + } wxMFileList; + + static wxMFileList *m_first; + static wxUint8 m_devnum; + + friend class wxMMDfileRegister; +public: + wxMediaFileSolve() : wxObject() {} + ~wxMediaFileSolve() {} + + /** It resolves using the extension of the specified filename + * @memo + * @return the multimedia codec + * @param filename + */ + static wxMMediaFile *ByExtension(const wxString& filename); + + /** It resolves using the real name of a codec + * @memo + * @return the multimedia codec + * @param devname + */ + static wxMMediaFile *ByName(const wxString& devname); + + /** It resolves using a mime type + * @memo + * @return the multimedia codec + * @param mimetype + */ + static wxMMediaFile *ByType(const wxString& mimetype); + + /** It lists all codecs currently registered in "names". "names" is allocated + * by it and devices returns the number of codecs the list contains + * @memo + * @return nothing + * @param names an array + * @param devices + */ + static void ListMDevice(wxString*& names, wxUint8& devices); +}; + +/// +class wxMMDfileRegister { +public: + /// + wxMMDfileRegister(wxMediaFileCreator cbk, char *mtype, char *ext, char *name); +}; + +#define MMD_REGISTER_FILE(mtype, name, class, ext) \ +static wxMMediaFile *wxMediaFileConstructor_##class() { return new class(); } \ +wxMMDfileRegister mmd_##class(wxMediaFileConstructor_##class, mtype, ext, name); + +//@} + +#endif diff --git a/utils/wxMMedia/mmtype.h b/utils/wxMMedia/mmtype.h new file mode 100644 index 0000000000..e65d00dbf4 --- /dev/null +++ b/utils/wxMMedia/mmtype.h @@ -0,0 +1,41 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: mmtype.h +// Purpose: wxMMedia (imported from wxSocket) +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// + +#ifndef __SOCKTYPEH__ +#define __SOCKTYPEH__ + +#ifdef __UNIX__ +#include +#endif + +/// Type to use for 8 bits unsigned integers +typedef unsigned char wxUint8; +/// Type to use for 16 bits unsigned integers +typedef unsigned short wxUint16; +/// Type to use for 32 bits unsigned integers +typedef unsigned long wxUint32; +#if HAVE_UINT64 +/// Type to use for 64 bits unsigned integers +typedef unsigned long long wxUint64; +#endif + +/// Type to use for 8 bits signed integers +typedef char wxInt8; +/// Type to use for 16 bits signed integers +typedef short wxInt16; +/// Type to use for 32 bits signed integers +typedef long wxInt32; +#if HAVE_UINT64 +/// Type to use for 64 bits signed integers +typedef long long wxInt64; +#endif + +#endif + diff --git a/utils/wxMMedia/sndaiff.cpp b/utils/wxMMedia/sndaiff.cpp new file mode 100644 index 0000000000..2e4b0cb84e --- /dev/null +++ b/utils/wxMMedia/sndaiff.cpp @@ -0,0 +1,218 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndaiff.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: February 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndaiff.h" +#endif + +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "wx/datstrm.h" +#include "sndaiff.h" +#include "sndpcm.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#define READ_DATA(n) m_istream->Read(tmp_buf,n) +#define WRITE_DATA(n) m_ostream->Write(tmp_buf,n) + +#define READ_STRING(s,n) \ + READ_DATA(n); \ + tmp_buf[n] = 0; \ + s = tmp_buf; + +#define WRITE_STRING(s,n) WRITE_DATA((const char *)s, n) + +#define READ32(i) \ + READ_DATA(4); \ + i = (unsigned long)tmp_buf[3] | \ + ((unsigned long)tmp_buf[2] << 8) | \ + ((unsigned long)tmp_buf[1] << 16) | \ + ((unsigned long)tmp_buf[0] << 24); + +#define WRITE32(i) \ + tmp_buf[3] = i & 0xFF; \ + tmp_buf[2] = (i >> 8) & 0xFF; \ + tmp_buf[1] = (i >> 16) & 0xFF; \ + tmp_buf[0] = (i >> 24) & 0xFF; \ + WRITE_DATA(4); + +#define READ16(i) \ + READ_DATA(2); \ + i = (unsigned short)tmp_buf[1] | \ + ((unsigned short)tmp_buf[0] << 8); + +wxSndAiffCodec::wxSndAiffCodec() + : wxSndFileCodec() +{ + m_sndtime.hours = -1; +} + +wxSndAiffCodec::wxSndAiffCodec(wxOutputStream& s, bool seekable) + : wxSndFileCodec(s, seekable) +{ + if (!seekable) + CacheIO(); + m_sndtime.hours = -1; +} + +wxSndAiffCodec::wxSndAiffCodec(wxInputStream& s, bool preload, bool seekable) + : wxSndFileCodec(s, preload, seekable) +{ + if (!seekable) + CacheIO(); + m_sndtime.hours = -1; +} + +wxSndAiffCodec::wxSndAiffCodec(const wxString& fname) + : wxSndFileCodec(fname) +{ + m_sndtime.hours = -1; +} + +wxUint32 wxSndAiffCodec::PrepareToPlay() +{ + char tmp_buf[5]; + wxString chunk_name; + + m_istream->SeekI(0, wxFromStart); + + wxSndFileCodec::m_mmerror = wxMMFILE_INVALID; + + READ_STRING(chunk_name, 4); + if (chunk_name != "FORM") + return 0; + m_istream->SeekI(4, wxFromCurrent); + + READ_STRING(chunk_name, 4); + if (chunk_name != "AIFF" && chunk_name != "AIFC") + return 0; + + // To check whether the file is good + m_spos = 0; + m_slen = 0; + m_sndformat.SetSampleRate(0); + while (1) { + READ_STRING(chunk_name, 4); + READ32(m_chunksize); + + if (chunk_name == "SSND") + ParseSSND(); + if (chunk_name == "COMM") + ParseCOMM(); + else + m_istream->SeekI(m_chunksize, wxFromCurrent); + + if (m_spos && m_sndformat.GetSampleRate()) + break; + } + + m_sndmode = wxSND_OUTPUT; + + wxUint32 sec1 = m_slen / m_sndformat.GetCodec()->GetByteRate(), + sec2 = sec1 % 3600; + + m_sndtime.hours = sec1 / 3600; + m_sndtime.minutes = sec2 / 60; + m_sndtime.seconds = sec2 % 60; + + wxSndFileCodec::m_mmerror = wxMMFILE_NOERROR; + + m_istream->SeekI(m_spos, wxFromStart); + return m_slen; +} + +void wxSndAiffCodec::ParseCOMM() +{ + wxDataInputStream data_s(*m_istream); + char tmp_buf[10]; + wxUint16 channels; + wxUint32 srate, num_samples; + wxUint16 bps; + + READ16(channels); + READ32(num_samples); + READ16(bps); + + srate = (wxUint32)data_s.ReadDouble(); + m_sndformat.SetSampleRate(srate); + m_sndformat.SetBps(bps); + m_sndformat.SetChannels(channels); + m_sndformat.SetByteOrder(wxSND_SAMPLE_BE); + m_sndformat.SetSign(wxSND_SAMPLE_UNSIGNED); + ChangeCodec(WXSOUND_PCM); + + m_istream->SeekI(m_chunksize-18, wxFromCurrent); +} + +void wxSndAiffCodec::ParseSSND() +{ + wxDataInputStream data_s(*m_istream); + char tmp_buf[10]; + + READ32(m_spos); + m_istream->SeekI(4, wxFromCurrent); + + m_slen = m_chunksize - m_spos; + m_spos += m_istream->TellI(); +} + +wxSndAiffCodec::~wxSndAiffCodec() +{ +} + +bool wxSndAiffCodec::OnNeedData(char *buf, wxUint32 size) +{ + m_istream->Read(buf, size); + return TRUE; +} + +bool wxSndAiffCodec::OnWriteData(char *buf, wxUint32 size) +{ + return ( !(m_ostream->Write(buf, size).LastError()) ); +} + +bool wxSndAiffCodec::PrepareToRecord(wxUint32 m_fsize) +{ +/* + wxUint32 total_size; + char tmp_buf[10]; + + m_ostream->SeekO(0, wxBeginPosition); + + m_ostream->Write("FORM", 4); + WRITE32(total_size); + + m_ostream->Write("AIFF", 4); + + WriteCOMM(); + WriteSSND(m_fsize); + +*/ + return TRUE; +} + +void wxSndAiffCodec::SetFile(wxInputStream& s, bool preload, bool seekable) +{ + wxMMediaFile::SetFile(s, preload, seekable); + if (!seekable) + CacheIO(); +} + +void wxSndAiffCodec::SetFile(wxOutputStream& s, bool seekable) +{ + wxMMediaFile::SetFile(s, seekable); + if (!seekable) + CacheIO(); +} diff --git a/utils/wxMMedia/sndaiff.h b/utils/wxMMedia/sndaiff.h new file mode 100644 index 0000000000..0a574e8f3e --- /dev/null +++ b/utils/wxMMedia/sndaiff.h @@ -0,0 +1,58 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndaiff.h +// Purpose: wxMMedia Aiff Codec +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: February 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_aiff_H__ +#define __SND_aiff_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmriff.h" +#include "sndfile.h" + +/// +class wxSndAiffCodec : public wxSndFileCodec { + /// + DECLARE_DYNAMIC_CLASS(wxSndAiffCodec) +public: + /// + wxSndAiffCodec(); + /// + wxSndAiffCodec(wxInputStream& s, bool preload = FALSE, bool seekable = TRUE); + /// + wxSndAiffCodec(wxOutputStream& s, bool seekable = TRUE); + /// + wxSndAiffCodec(const wxString& fname); + /// + virtual ~wxSndAiffCodec(); + + virtual bool OnNeedData(char *buf, wxUint32 size); + virtual bool OnWriteData(char *buf, wxUint32 size); + + virtual wxUint32 PrepareToPlay(); + virtual bool PrepareToRecord(wxUint32 file_size); + + virtual void SetFile(wxInputStream& s, bool preload = FALSE, + bool seekable = FALSE); + virtual void SetFile(wxOutputStream& s, + bool seekable = FALSE); +protected: + void ParseCOMM(); + void ParseSSND(); + + void WriteCOMM(); + void WriteSSND(wxUint32 file_size); + +protected: + wxUint32 m_spos, m_slen; + wxUint32 m_chunksize; +}; + +#endif diff --git a/utils/wxMMedia/sndau.cpp b/utils/wxMMedia/sndau.cpp new file mode 100644 index 0000000000..9c46880411 --- /dev/null +++ b/utils/wxMMedia/sndau.cpp @@ -0,0 +1,114 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndau.cpp +// Purpose: wxMMedia Sun Audio File Codec +// Author: Guilhem Lavaux +// Created: 1998 +// Updated: +// Copyright: (C) 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndau.h" +#endif + +#include "mmriff.h" +#include "sndfile.h" +#include "sndau.h" + +#define AU_ISDN_ULAW 1 +#define AU_PCM_8BITS 2 +#define AU_PCM_16BITS 3 +#define AU_ADPCM 23 + +wxSndAuCodec::wxSndAuCodec() + : wxSndFileCodec() +{ +} + +wxSndAuCodec::wxSndAuCodec(wxInputStream& s, bool preload, bool seekable) + : wxSndFileCodec(s, preload, seekable) +{ +} + +wxSndAuCodec::wxSndAuCodec(wxOutputStream& s, bool seekable) + : wxSndFileCodec(s, seekable) +{ +} + +wxSndAuCodec::wxSndAuCodec(const wxString& fname) + : wxSndFileCodec(fname) +{ +} + +wxSndAuCodec::~wxSndAuCodec() +{ +} + +wxUint32 wxSndAuCodec::PrepareToPlay() +{ + wxString id; + char temp_buf[5]; + int offset, srate, codec, ch_count; + size_t len; + + m_istream->SeekI(0); + + m_istream->Read(temp_buf, 4); + temp_buf[4] = 0; + + id = temp_buf; + if (id != ".snd") { + m_mmerror = wxMMFILE_INVALID; + return 0; + } + +#define READ_BE_32(i) \ +m_istream->Read(temp_buf, 4); \ +i = (unsigned long)temp_buf[0] << 24; \ +i |= (unsigned long)temp_buf[1] << 16; \ +i |= (unsigned long)temp_buf[2] << 8; \ +i |= (unsigned long)temp_buf[3]; + + READ_BE_32(offset); + READ_BE_32(len); + READ_BE_32(codec); + READ_BE_32(srate); + READ_BE_32(ch_count); + + m_sndformat.SetSampleRate(srate); + m_sndformat.SetChannels(ch_count); + switch (codec) { + case AU_ISDN_ULAW: + ChangeCodec(WXSOUND_ULAW); + break; + case AU_PCM_8BITS: + ChangeCodec(WXSOUND_PCM); + m_sndformat.SetByteOrder(wxSND_SAMPLE_LE); + m_sndformat.SetSign(wxSND_SAMPLE_SIGNED); + break; + case AU_PCM_16BITS: + ChangeCodec(WXSOUND_PCM); + m_sndformat.SetByteOrder(wxSND_SAMPLE_LE); + m_sndformat.SetSign(wxSND_SAMPLE_SIGNED); + break; + case AU_ADPCM: + ChangeCodec(WXSOUND_ADPCM); + break; + } + return len; +} + +bool wxSndAuCodec::OnNeedData(char *buf, wxUint32 size) +{ + return m_istream->Read(buf, size).LastError(); +} + +bool wxSndAuCodec::OnWriteData(char *buf, wxUint32 size) +{ + return m_ostream->Write(buf, size).LastError(); +} + +bool wxSndAuCodec::PrepareToRecord(wxUint32 file_size) +{ + return FALSE; +} diff --git a/utils/wxMMedia/sndau.h b/utils/wxMMedia/sndau.h new file mode 100644 index 0000000000..ee8a2762ce --- /dev/null +++ b/utils/wxMMedia/sndau.h @@ -0,0 +1,47 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndau.h +// Purpose: wxMMedia Sun Audio File Codec +// Author: Guilhem Lavaux +// Created: 1998 +// Updated: +// Copyright: (C) 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_au_H__ +#define __SND_au_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmriff.h" +#include "sndfile.h" + +/// +class wxSndAuCodec : public wxSndFileCodec { + /// + DECLARE_DYNAMIC_CLASS(wxSndAuCodec) +public: + /// + wxSndAuCodec(); + /// + wxSndAuCodec(wxInputStream& s, bool preload = FALSE, bool seekable = TRUE); + /// + wxSndAuCodec(wxOutputStream& s, bool seekable = TRUE); + /// + wxSndAuCodec(const wxString& fname); + /// + virtual ~wxSndAuCodec(); + + bool OnNeedData(char *buf, wxUint32 size); + bool OnWriteData(char *buf, wxUint32 size); + + wxUint32 PrepareToPlay(); + bool PrepareToRecord(wxUint32 file_size); + +protected: + wxUint32 m_spos, m_slen; + wxUint32 m_chunksize; +}; + +#endif diff --git a/utils/wxMMedia/sndfile.cpp b/utils/wxMMedia/sndfile.cpp new file mode 100644 index 0000000000..798969a6c9 --- /dev/null +++ b/utils/wxMMedia/sndfile.cpp @@ -0,0 +1,323 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndfile.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndfile.h" +#endif + +#include "mmedia.h" +#include "sndfile.h" +#ifdef WX_PRECOMP +#include +#else +#include +#endif +#include +#include "sndfrmt.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxSndFileCodec::wxSndFileCodec() + : wxMMediaFile(), wxSndBuffer(), + m_fstate(wxSFILE_STOPPED) +{ +} + +wxSndFileCodec::wxSndFileCodec(wxOutputStream& s, bool seekable) + : wxMMediaFile(s, seekable), + wxSndBuffer(), + m_fstate(wxSFILE_STOPPED) +{ +} + +wxSndFileCodec::wxSndFileCodec(wxInputStream& s, bool preload, bool seekable) + : wxMMediaFile(s, preload, seekable), + wxSndBuffer(), + m_fstate(wxSFILE_STOPPED) +{ +} + +wxSndFileCodec::wxSndFileCodec(const wxString& fname) + : wxMMediaFile(fname), wxSndBuffer(), + m_fstate(wxSFILE_STOPPED) +{ +} + +wxSndFileCodec::~wxSndFileCodec() +{ +} + +void wxSndFileCodec::Play(wxSound& snd) +{ + if (m_fstate != wxSFILE_STOPPED || IsSet(wxSND_BUFLOCKED)) + return; + + if (!(m_fsize = PrepareToPlay())) + return; + + m_fpos = 0; + m_fstate = wxSFILE_PLAYING; + + Set(wxSND_BUFREADY | wxSND_KEEPQUEUED); + snd.QueueBuffer(*this); +} + +void wxSndFileCodec::Stop(wxSound& snd) +{ + if (m_fstate == wxSFILE_STOPPED) + return; + + snd.UnqueueBuffer(*this); + Clear(wxSND_BUFREADY | wxSND_KEEPQUEUED); + m_fstate = wxSFILE_STOPPED; +} + +void wxSndFileCodec::Record(wxSound& snd, + const wxSoundDataFormat& format, + wxUint32 seconds) +{ + wxUint32 byterate; + + if (m_fstate != wxSFILE_STOPPED) + return; + + m_sndformat = format; + byterate = m_sndformat.GetCodec()->GetByteRate(); + + m_fsize = seconds*byterate; + if (!PrepareToRecord(m_fsize)) + return; + if (IsSet(wxSND_BUFLOCKED)) + return; + + wxUint32 sec1 = m_fsize / byterate, + sec2 = sec1 % 3600; + + m_sndtime.hours = sec1 / 3600; + m_sndtime.minutes = sec2 / 60; + m_sndtime.seconds = sec2 % 60; + + m_fdone = m_fpos = 0; + m_fstate = wxSFILE_RECORDING; + + m_sndmode = wxSND_INPUT; + + Set(wxSND_BUFREADY | wxSND_KEEPQUEUED); + snd.QueueBuffer(*this); +} + +void wxSndFileCodec::OnNeedOutputData(char *data, wxUint32& size) +{ + wxUint32 datas_left = m_fsize-m_fpos; + + if (m_fstate != wxSFILE_PLAYING) { + size = 0; + return; + } + + if (!datas_left) { + size = 0; + m_fpos = 0; + m_fstate = wxSFILE_STOPPED; + Clear(wxSND_KEEPQUEUED); + return; + } + + if (size > datas_left) + size = datas_left; + + if (!OnNeedData(data, size)) { + size = 0; + m_fpos = 0; + m_fstate = wxSFILE_STOPPED; + Clear(wxSND_KEEPQUEUED); + return; + } + + m_fpos += size; +} + +void wxSndFileCodec::OnBufferInFinished(char *iobuf, wxUint32& size) +{ + wxUint32 datas_left = m_fsize-m_fdone; + + if (m_fstate != wxSFILE_RECORDING) { + size = 0; + return; + } + + if (!datas_left) { + size = 0; + Clear(wxSND_KEEPQUEUED); // To be sure. + return; + } + + if (size > datas_left) + size = datas_left; + + OnWriteData(iobuf, size); + m_fdone += size; +} + +wxMMtime wxSndFileCodec::GetPosition() +{ + wxMMtime mm_time; + wxUint32 sec1, sec2; + wxUint32 byterate; + + byterate = m_sndformat.GetCodec()->GetByteRate(); + + if (m_fpos && byterate) { + sec1 = m_fpos / byterate; + sec2 = sec1 % 3600; + mm_time.hours = sec1 / 3600; + mm_time.minutes = sec2 / 60; + mm_time.seconds = sec2 % 60; + } else { + mm_time.hours = 0; + mm_time.minutes = 0; + mm_time.seconds = 0; + } + + return mm_time; +} + +wxMMtime wxSndFileCodec::GetLength() +{ + if (m_sndtime.hours == -1 && m_istream) + PrepareToPlay(); + + return m_sndtime; +} + +bool wxSndFileCodec::TranslateBuffer(wxSndBuffer& buf) +{ +#define TMP_BUFSIZE 10240 + + wxUint32 buf_size; + wxStreamBuffer *tmp_buf; + wxSoundCodec *codec_in, *codec_out; + wxSoundDataFormat std_format; + + if (!m_ostream || !buf.RestartBuffer(wxSND_OUTPUT)) + return FALSE; + + m_sndformat = buf.GetFormat(); + codec_in = buf.GetCurrentCodec(); + + m_fdone = 0; + + if (!PrepareToRecord(m_fsize)) + return FALSE; + + codec_out = GetCurrentCodec(); + m_fsize = (int)(((float)buf.GetSize() / codec_in->GetByteRate()) * + codec_out->GetByteRate()); + + if (!PrepareToRecord(m_fsize)) + return FALSE; + + codec_out = GetCurrentCodec(); + codec_in->InitIO(m_sndformat); + codec_out->InitIO(m_sndformat); + + tmp_buf = new wxStreamBuffer(wxStreamBuffer::read_write); + tmp_buf->Fixed(TRUE); + tmp_buf->Flushable(FALSE); + tmp_buf->SetBufferIO(TMP_BUFSIZE); + + m_fstate = wxSFILE_RECORDING; + + while (m_fdone < m_fsize) { + tmp_buf->ResetBuffer(); + codec_in->SetOutStream(tmp_buf); + codec_in->Decode(); + + tmp_buf->ResetBuffer(); + codec_out->SetInStream(tmp_buf); + codec_out->Encode(); + + buf.OnBufferOutFinished(); + } + delete tmp_buf; + + m_fstate = wxSFILE_STOPPED; + + return TRUE; +} + +bool wxSndFileCodec::RestartBuffer(wxSndMode mode) +{ + if (IsSet(wxSND_BUFLOCKED)) + return FALSE; + + m_fdone = 0; + m_fpos = 0; + + if (mode == wxSND_OUTPUT && m_istream) { + m_fsize = PrepareToPlay(); + m_fstate = wxSFILE_PLAYING; + return TRUE; + } + if (mode == wxSND_INPUT && m_ostream) { + m_fsize = 0; + m_fstate = wxSFILE_RECORDING; + return TRUE; + } + + return FALSE; +} + +wxUint32 wxSndFileCodec::GetSize() const +{ + return m_fsize; +} + +wxUint32 wxSndFileCodec::Available() const +{ + return m_fsize-m_fpos; +} + +// +// Simple API +// +static wxSoundDevice *dev_snd = NULL; + +bool wxSndFileCodec::StartPlay() +{ + if (!dev_snd) + dev_snd = new wxSoundDevice; + + Play(*dev_snd); + + return TRUE; +} + +void wxSndFileCodec::StopPlay() +{ + if (!dev_snd) + return; + + Stop(*dev_snd); + m_fpos = 0; +} + +class wxSoundModule : public wxModule { + DECLARE_DYNAMIC_CLASS(wxSoundModule) +public: + virtual bool OnInit() { return TRUE; } + virtual void OnExit() { + if (dev_snd) + delete dev_snd; + } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxSoundModule, wxModule) diff --git a/utils/wxMMedia/sndfile.h b/utils/wxMMedia/sndfile.h new file mode 100644 index 0000000000..2a1c7e5fa5 --- /dev/null +++ b/utils/wxMMedia/sndfile.h @@ -0,0 +1,91 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndfile.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_file_H__ +#define __SND_file_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmfile.h" +#include "sndsnd.h" + +/// +class wxSndFileCodec : public wxMMediaFile, public wxSndBuffer { + /// + DECLARE_ABSTRACT_CLASS(wxSndFileCodec) +public: + + typedef enum { + wxSFILE_STOPPED, + wxSFILE_PLAYING, + wxSFILE_RECORDING + } FileState; + +protected: + wxUint32 m_fsize, m_fpos, m_fdone; + FileState m_fstate; + wxMMtime m_sndtime; +public: + + /// + wxSndFileCodec(); + /// + wxSndFileCodec(wxInputStream& s, bool preload, bool seekable); + /// + wxSndFileCodec(wxOutputStream& s, bool seekable); + /// + wxSndFileCodec(const wxString& fname); + /// + virtual ~wxSndFileCodec(); + + /// + void Play(wxSound& snd); + /// + void Stop(wxSound& snd); + /// + void Record(wxSound& snd, + const wxSoundDataFormat& format, wxUint32 seconds); + + /// + void OnNeedOutputData(char *data, wxUint32& size); + /// + void OnBufferInFinished(char *iobuf, wxUint32& size); + + /// + virtual bool OnNeedData(char *buf, wxUint32 size) = 0; + /// + virtual bool OnWriteData(char *buf, wxUint32 size) = 0; + /// + virtual wxUint32 PrepareToPlay() = 0; + /// + virtual bool PrepareToRecord(wxUint32 file_size) = 0; + /// + virtual bool TranslateBuffer(wxSndBuffer& buf); + /// + virtual bool RestartBuffer(wxSndMode mode); + /// + virtual wxUint32 GetSize() const; + /// + virtual wxUint32 Available() const; + /// + virtual wxMMtime GetLength(); + + /// + wxMMtime GetPosition(); + + /// + virtual bool StartPlay(); + /// + virtual void StopPlay(); +}; + +#endif diff --git a/utils/wxMMedia/sndfrag.cpp b/utils/wxMMedia/sndfrag.cpp new file mode 100644 index 0000000000..cd4a76bce8 --- /dev/null +++ b/utils/wxMMedia/sndfrag.cpp @@ -0,0 +1,268 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndfrag.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndfrag.h" +#endif +#include +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "sndfrag.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxFragmentBuffer::wxFragmentBuffer(wxSound& io_drv) + : m_iodrv(&io_drv), m_maxoq(0), m_maxiq(0), + m_optrs(NULL), m_iptrs(NULL), m_lstoptrs(NULL), m_lstiptrs(NULL), + m_buf2free(FALSE), m_dontq(FALSE), m_freeing(FALSE) +{ +} + +wxFragmentBuffer::~wxFragmentBuffer() +{ +} + +void wxFragmentBuffer::AbortBuffer(wxSndBuffer *buf) +{ + for (wxUint8 i=0;iMember(buf)) { + if (m_lstoptrs[i].state == wxBUFFER_PLAYING) + // TODO: Do something. + ; + m_lstoptrs[i].state = wxBUFFER_TOFREE; + } + + for (wxUint8 i=0;iMember(buf)) { + if (m_lstiptrs[i].state == wxBUFFER_PLAYING) + // Do something. + ; + m_lstiptrs[i].state = wxBUFFER_TOFREE; + } +} + +wxFragmentBuffer::wxFragBufPtr *wxFragmentBuffer::FindFreeBuffer( + wxFragBufPtr *list, wxUint8 max_queue) +{ + if (!list) + return NULL; + + for (wxUint8 i=0;iOnSetupDriver(*buf, wxSND_OUTPUT)) + return FALSE; + + while (1) { + // Find the first free (at least partly free) output buffer + ptr = FindFreeBuffer(m_lstoptrs, m_maxoq); + // No free : go out ! + if (!ptr) + return FALSE; + + // Find the end of the buffer + raw_buf = ptr->data + ptr->ptr; + rawbuf_size = ptr->size - ptr->ptr; + + // Fill it up + buf->OnNeedOutputData(raw_buf, rawbuf_size); + + // No data to fill the buffer: dequeue the current wxSndBuffer + if (!rawbuf_size) { + if (buf->IsNotSet(wxSND_KEEPQUEUED)) { + buf->Set(wxSND_UNQUEUEING); + m_iodrv->m_buffers.DeleteObject(buf); + } + return TRUE; + } + + // Data: append it to the list + ptr->buffers->Append(buf); + + ptr->ptr += rawbuf_size; + + // Output buffer full: send it to the driver + if (ptr->ptr == ptr->size) { + ptr->state = wxBUFFER_FFILLED; + OnBufferFilled(ptr, wxSND_OUTPUT); + } + } +} + +bool wxFragmentBuffer::NotifyInputBuffer(wxSndBuffer *buf) +{ + wxFragBufPtr *ptr; + char *raw_buf; + wxUint32 rawbuf_size; + + if (!m_iodrv->OnSetupDriver(*buf, wxSND_INPUT)) + return FALSE; + + while (1) { + ptr = FindFreeBuffer(m_lstiptrs, m_maxiq); + if (!ptr) + return FALSE; + + raw_buf = ptr->data + ptr->ptr; + rawbuf_size = ptr->size - ptr->ptr; + + rawbuf_size = (buf->Available() < rawbuf_size) ? buf->Available() : rawbuf_size; + + if (!rawbuf_size) { + + if (buf->IsNotSet(wxSND_KEEPQUEUED)) { + buf->Set(wxSND_UNQUEUEING); + m_iodrv->m_buffers.DeleteObject(buf); + } + + // Get data now when there isn't anymore buffer in the queue + if (!LastBuffer() && ptr->ptr) { + ptr->state = wxBUFFER_FFILLED; + if (!OnBufferFilled(ptr, wxSND_INPUT)) + return FALSE; + } + return TRUE; + } + ptr->buffers->Append(buf); + + ptr->ptr += rawbuf_size; + + // Input buffer full => get data + if (ptr->ptr == ptr->size) { + ptr->state = wxBUFFER_FFILLED; + if (!OnBufferFilled(ptr, wxSND_INPUT)) + return FALSE; + } + } + return TRUE; +} + +void wxFragmentBuffer::FreeBufToFree(bool force) +{ + wxUint8 i; + // Garbage collecting + + m_dontq = TRUE; + m_buf2free = FALSE; + + for (i=0;idata; + size = ptr->size; + + node = ptr->buffers->First(); + + while (node) { + buf = (wxSndBuffer *)node->Data(); + + if (buf->GetMode() == wxSND_OUTPUT) { + buf->OnBufferOutFinished(); + } else { + data_read = buf->OnBufferInFinished(data, size); + + data += data_read; + size -= data_read; + } + + if (buf->IsSet(wxSND_UNQUEUEING)) + buf->Clear(wxSND_UNQUEUEING | wxSND_BUFLOCKED | wxSND_BUFREADY); + + delete node; + node = ptr->buffers->First(); + } + + ptr->ptr = 0; + ptr->state = wxBUFFER_FREE; +} + +void wxFragmentBuffer::OnBufferFinished(wxFragBufPtr *ptr) +{ + wxNode *node; + wxSndBuffer *buf; + bool ret = TRUE; + + if (m_freeing) { + ptr->state = wxBUFFER_TOFREE; + m_buf2free = TRUE; + return; + } + m_freeing = TRUE; + + // Clean up the old buffer. + if (ptr && ptr->state != wxBUFFER_FREE) + ClearBuffer(ptr); + + // Garbage collecting ... + if (m_buf2free) + FreeBufToFree(); + + // If we are queueing, return immediately. + if (m_dontq) { + m_freeing = FALSE; + return; + } + + node = m_iodrv->m_buffers.First(); + + while (node && ret) { + buf = (wxSndBuffer *)node->Data(); + node = node->Next(); + + buf->HardLock(); + + // Stop request on this buffer. + if (buf->IsSet(wxSND_BUFSTOP)) { + buf->Clear(wxSND_BUFSTOP); + continue; + } + if (buf->GetMode() == wxSND_OUTPUT) + ret = NotifyOutputBuffer(buf); + else + ret = NotifyInputBuffer(buf); + + buf->HardUnlock(); + } + m_freeing = FALSE; +} diff --git a/utils/wxMMedia/sndfrag.h b/utils/wxMMedia/sndfrag.h new file mode 100644 index 0000000000..8acb31f9cf --- /dev/null +++ b/utils/wxMMedia/sndfrag.h @@ -0,0 +1,103 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndfrag.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __SND_frag_H__ +#define __SND_frag_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "sndsnd.h" + +/// +class wxFragmentBuffer { +protected: + wxSound *m_iodrv; + + /// + wxUint8 m_maxoq, m_maxiq; + + /// + typedef enum { + wxBUFFER_FREE, + wxBUFFER_FFILLED, + wxBUFFER_TOFREE + } BufState; +public: + /// + typedef struct { + char *data; + /// + char *user_data; + /// + wxUint32 size, ptr; + /// + wxList *buffers; + /// + BufState state; + } wxFragBufPtr; +protected: + /// + wxFragBufPtr *m_optrs, *m_iptrs; + /// + wxFragBufPtr *m_lstoptrs, *m_lstiptrs; + /// + bool m_buf2free, m_dontq, m_freeing; +public: + /// + wxFragmentBuffer(wxSound& io_drv); + /// + virtual ~wxFragmentBuffer(); + + /// + virtual void AllocIOBuffer() = 0; + /// + virtual void FreeIOBuffer() = 0; + + /// + void AbortBuffer(wxSndBuffer *buf); + + /// + wxFragBufPtr *FindFreeBuffer(wxFragBufPtr *list, wxUint8 max_queue); + /// + bool NotifyOutputBuffer(wxSndBuffer *buf); + /// + bool NotifyInputBuffer(wxSndBuffer *buf); + + /// + void OnBufferFinished(wxFragBufPtr *ptr); + + /// + virtual bool OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode) = 0; + + /// + inline wxSndBuffer *LastBuffer() { + wxNode *node = m_iodrv->m_buffers.Last(); + + if (!node) return NULL; + return (wxSndBuffer *)node->Data(); + } + /// + inline wxSndBuffer *FirstBuffer() { + wxNode *node = m_iodrv->m_buffers.First(); + + if (!node) return NULL; + return (wxSndBuffer *)node->Data(); + } +protected: + void FreeBufToFree(bool force = FALSE); + void ClearBuffer(wxFragBufPtr *ptr); +}; + +#endif diff --git a/utils/wxMMedia/sndfrmt.cpp b/utils/wxMMedia/sndfrmt.cpp new file mode 100644 index 0000000000..fb933b4be9 --- /dev/null +++ b/utils/wxMMedia/sndfrmt.cpp @@ -0,0 +1,266 @@ +#ifdef __GNUG__ +#pragma implementation "sndfrmt.h" +#endif +#include "sndsnd.h" +#include "sndfrmt.h" +#include "sndpcm.h" +#include + +// ---------------------------------------------------------------------------- +// wxSoundDataFormat +// ---------------------------------------------------------------------------- + +wxSoundDataFormat::wxSoundDataFormat() +{ + m_srate = 22050; + m_bps = 8; + m_channels = 1; + m_codno = 1; + m_codec = NULL; + m_codchange = FALSE; + m_codcreate = TRUE; +} + +wxSoundDataFormat::~wxSoundDataFormat() +{ + wxDELETE(m_codec); +} + +void wxSoundDataFormat::SetChannels(int channels) +{ + m_channels = channels; +} + +void wxSoundDataFormat::SetBps(int bps) +{ + m_bps = bps; + CodecChange(); +} + +void wxSoundDataFormat::SetSign(int sign) +{ + m_sign = sign; + CodecChange(); +} + +void wxSoundDataFormat::SetByteOrder(int byteorder) +{ + m_byteorder = byteorder; + CodecChange(); +} + +void wxSoundDataFormat::SetCodecNo(int codno) +{ + m_codno = codno; + m_codchange = TRUE; + CodecChange(); +} + +wxSoundCodec *wxSoundDataFormat::GetCodec() +{ + if (!m_codcreate) + return NULL; + + if (m_codchange) + wxDELETEA(m_codec); + + if (m_codec) + return m_codec; + + m_codchange = FALSE; + m_codec = wxSoundCodec::Get(m_codno); + + return m_codec; +} + +void wxSoundDataFormat::CodecChange() +{ + wxSoundCodec *codec = GetCodec(); + + if (!codec) + return; + + switch (m_codno) { + case WXSOUND_PCM: { + wxSoundPcmCodec *pcm_codec = (wxSoundPcmCodec *)codec; + + pcm_codec->SetBits(m_bps); + pcm_codec->SetByteOrder(m_byteorder); + pcm_codec->SetSign(m_sign); + break; + } + default: + break; + } +} + +wxSoundDataFormat& wxSoundDataFormat::operator =(const wxSoundDataFormat& format) +{ + wxDELETE(m_codec); + + m_srate = format.m_srate; + m_bps = format.m_bps; + m_channels = format.m_channels; + m_codno = format.m_codno; + m_sign = format.m_sign; + m_byteorder = format.m_byteorder; + + return *this; +} + +bool wxSoundDataFormat::operator ==(const wxSoundDataFormat& format) const +{ + if (m_codno != format.m_codno || m_srate != format.m_srate || + m_bps != format.m_bps || m_channels != format.m_channels) + return FALSE; + + if (m_codno == WXSOUND_PCM && + (m_sign != format.m_sign || m_byteorder != format.m_byteorder)) + return FALSE; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxSoundCodec +// ---------------------------------------------------------------------------- + +#include "sndpcm.h" +//#include "sndadpcm.h" +//#include "sndalaw.h" +#include "sndmulaw.h" + +static wxClassInfo *l_sound_formats[] = { + NULL, + CLASSINFO(wxSoundPcmCodec), + NULL, // CLASSINFO(wxSoundAdpcmCodec), + NULL, + NULL, + NULL, + NULL, // CLASSINFO(wxSoundAlawCodec), + NULL // CLASSINFO(wxSoundMulawCodec) +}; + +static int l_nb_formats = WXSIZEOF(l_sound_formats); + +wxSoundCodec::wxSoundCodec() +{ + m_in_sound = NULL; + m_out_sound = NULL; + m_init = TRUE; +} + +wxSoundCodec::~wxSoundCodec() +{ +} + +void wxSoundCodec::InitIO(const wxSoundDataFormat& format) +{ + m_io_format = format; +} + +void wxSoundCodec::InitMode(int mode) +{ + wxStreamBuffer *buf_snd; + + m_mode = (mode == 0) ? ENCODING : DECODING; + if (!m_chain_codec) { + if (mode == ENCODING) { + m_out_sound = new wxStreamBuffer(*this, wxStreamBuffer::write); + m_out_sound->SetBufferIO(1024); + } else { + m_in_sound = new wxStreamBuffer(*this, wxStreamBuffer::read); + m_in_sound->SetBufferIO(1024); + } + } + if (m_chain_codec) { + if (m_chain_before) { + m_chain_codec->SetInStream(m_in_sound); + buf_snd = new wxStreamBuffer(wxStreamBuffer::read_write); + buf_snd->Fixed(FALSE); + m_chain_codec->SetOutStream(buf_snd); + m_chain_codec->Decode(); + buf_snd->Seek(0, wxFromStart); + m_in_sound = buf_snd; + } else { + buf_snd = new wxStreamBuffer(wxStreamBuffer::read_write); + buf_snd->Fixed(FALSE); + + m_chain_codec->SetInStream(buf_snd); + m_chain_codec->SetOutStream(m_out_sound); + m_out_sound = buf_snd; + + buf_snd->Seek(0, wxFromStart); + } + } +} + +void wxSoundCodec::ExitMode() +{ + if (m_chain_codec) { + if (m_chain_before) { + delete m_in_sound; + m_in_sound = m_chain_codec->GetInStream(); + } else { + delete m_out_sound; + m_out_sound = m_chain_codec->GetOutStream(); + } + } +} + +bool wxSoundCodec::ChainCodecBefore(wxSoundDataFormat& format) +{ + m_chain_codec = format.GetCodec(); + + if (!m_chain_codec) + return FALSE; + + m_chain_before = TRUE; + return TRUE; +} + +bool wxSoundCodec::ChainCodecAfter(wxSoundDataFormat& format) +{ + m_chain_codec = format.GetCodec(); + + if (!m_chain_codec) + return FALSE; + + m_chain_before = FALSE; + return TRUE; +} + +void wxSoundCodec::CopyToOutput() +{ + m_out_sound->Write(m_in_sound); +} + +size_t wxSoundCodec::Available() +{ + return m_io_sndbuf->Available(); +} + +size_t wxSoundCodec::OnSysRead(void *buffer, size_t bsize) +{ + wxUint32 s = bsize; + m_io_sndbuf->OnNeedOutputData((char *)buffer, s); + return bsize; +} + +size_t wxSoundCodec::OnSysWrite(const void *buffer, size_t bsize) +{ + wxUint32 s = bsize; + m_io_sndbuf->OnBufferInFinished((char *)buffer, s); + return bsize; +} + +wxSoundCodec *wxSoundCodec::Get(int no) +{ + if (no < 0 || no >= l_nb_formats) + return NULL; + + if (!l_sound_formats[no]) + return NULL; + + return (wxSoundCodec *)l_sound_formats[no]->CreateObject(); +} diff --git a/utils/wxMMedia/sndfrmt.h b/utils/wxMMedia/sndfrmt.h new file mode 100644 index 0000000000..feb0ad62d2 --- /dev/null +++ b/utils/wxMMedia/sndfrmt.h @@ -0,0 +1,119 @@ +#ifndef __SNDFRMT_H__ +#define __SNDFRMT_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include + +class wxSndBuffer; + +// Standard Microsoft types (why change ?) +#define WXSOUND_PCM 0x0001 +#define WXSOUND_ADPCM 0x0002 +#define WXSOUND_ALAW 0x0006 +#define WXSOUND_ULAW 0x0007 + +class wxSoundCodec; +class wxSoundDataFormat { + public: + wxSoundDataFormat(); + ~wxSoundDataFormat(); + + void SetSampleRate(int srate) { m_srate = srate; } + void SetChannels(int channels); + void SetStereo(bool on); + void SetCodecNo(int no); + void SetCodecCreate(bool create) { m_codcreate = create; } + + int GetSampleRate() const { return m_srate; } + int GetChannels() const { return m_channels; } + bool GetStereo() const { return (m_channels == 2); } + int GetCodecNo() const { return m_codno; } + + wxSoundCodec *GetCodec(); + + wxSoundDataFormat& operator =(const wxSoundDataFormat& format); + bool operator ==(const wxSoundDataFormat& format) const; + bool operator !=(const wxSoundDataFormat& format) const + { return !(operator ==(format)); } + + /// PCM format + void SetByteOrder(int order); + void SetSign(int sign); + int GetByteOrder() const { return m_byteorder; } + int GetSign() const { return m_sign; } + + void SetBps(int bps); + int GetBps() const { return m_bps; } + + protected: + void CodecChange(); + + protected: + int m_srate, m_bps, m_channels, m_codno; + int m_byteorder, m_sign; + bool m_codchange, m_codcreate; + wxSoundCodec *m_codec; +}; + +class wxSoundCodec : public wxObject, public wxStreamBase { + DECLARE_ABSTRACT_CLASS(wxSoundCodec) + public: + wxSoundCodec(); + virtual ~wxSoundCodec(); + + void SetIOBuffer(wxSndBuffer *sndbuf) { m_io_sndbuf = sndbuf; } + size_t Available(); + + void InitIO(const wxSoundDataFormat& format); + void InitMode(int mode); + void ExitMode(); + + inline void SetInStream(wxStreamBuffer *s) + { m_in_sound = s; } + inline void SetOutStream(wxStreamBuffer *s) + { m_out_sound = s; } + inline wxStreamBuffer *GetInStream() const { return m_in_sound; } + inline wxStreamBuffer *GetOutStream() const { return m_out_sound; } + + inline bool Good() const { return (m_in_sound->Stream()->LastError() == wxStream_NOERROR) && (m_out_sound->Stream()->LastError() == wxStream_NOERROR); } + + virtual size_t GetByteRate() const = 0; + virtual wxSoundDataFormat GetPreferredFormat(int codec = 0) const = 0; + + virtual void Decode() = 0; + virtual void Encode() = 0; + + static wxSoundCodec *Get(int no); + + protected: + void CopyToOutput(); + + unsigned short Convert8_16(unsigned char s) { return (s & 0xff) << 8; } + unsigned char Convert16_8(unsigned short s) { return (s & 0xff00) >> 8; } + + bool ChainCodecBefore(wxSoundDataFormat& cod_to); + bool ChainCodecAfter(wxSoundDataFormat& cod_to); + + // ------------- + // wxStream part + // ------------- + size_t OnSysWrite(const void *buffer, size_t bsize); + size_t OnSysRead(void *buffer, size_t bsize); + + protected: + wxSndBuffer *m_io_sndbuf; + wxSoundDataFormat m_io_format; + wxStreamBuffer *m_in_sound, *m_out_sound; + wxSoundCodec *m_chain_codec; + bool m_init, m_chain_before; + + enum { + ENCODING = 0, + DECODING + } m_mode; +}; + +#endif diff --git a/utils/wxMMedia/sndmulaw.cpp b/utils/wxMMedia/sndmulaw.cpp new file mode 100644 index 0000000000..f42e5a464e --- /dev/null +++ b/utils/wxMMedia/sndmulaw.cpp @@ -0,0 +1,85 @@ +#ifdef __GNUG__ +#pragma implementation "sndmulaw.h" +#endif + +#include "sndsnd.h" +#include "sndfrmt.h" +#include "sndmulaw.h" +#include "adpcm/g72x.h" + +wxSoundMulawCodec::wxSoundMulawCodec() + : wxSoundCodec() +{ +} + +wxSoundMulawCodec::~wxSoundMulawCodec() +{ +} + +void wxSoundMulawCodec::Decode() +{ + int smp; + wxSoundDataFormat pref_frmt; + + pref_frmt = GetPreferredFormat(0); + if (m_io_format != pref_frmt) + ChainCodecAfter(pref_frmt); + + InitMode(DECODING); + + while (!Good()) { + smp = ulaw2linear(m_in_sound->GetChar()); +#ifdef USE_BE_MACH + m_out_sound->PutChar((smp & 0xff00) >> 8); + m_out_sound->PutChar(smp & 0xff); +#else + m_out_sound->PutChar(smp & 0xff); + m_out_sound->PutChar((smp & 0xff00) >> 8); +#endif + } +} + +void wxSoundMulawCodec::Encode() +{ + int smp; + wxSoundDataFormat pref_frmt; + + pref_frmt = GetPreferredFormat(0); + if (m_io_format != pref_frmt) + ChainCodecBefore(pref_frmt); + + InitMode(ENCODING); + + while (!Good()) { +#ifdef USE_BE_MACH + smp = ((unsigned short)m_in_sound->GetChar()) << 8; + smp |= m_in_sound->GetChar() & 0xff; +#else + smp = m_in_sound->GetChar() & 0xff; + smp |= ((unsigned short)m_in_sound->GetChar()) << 8; +#endif + m_out_sound->PutChar(linear2ulaw(smp)); + } +} + +size_t wxSoundMulawCodec::GetByteRate() const +{ + return m_srate; +} + +wxSoundDataFormat wxSoundMulawCodec::GetPreferredFormat(int WXUNUSED(no)) const +{ + wxSoundDataFormat format; + + format.SetCodecNo(WXSOUND_PCM); + format.SetSampleRate(m_srate); + format.SetBps(16); + format.SetChannels(1); + format.SetSign(wxSND_SAMPLE_SIGNED); +#ifdef USE_BE_MACH + format.SetByteOrder(wxSND_SAMPLE_BE); +#else + format.SetByteOrder(wxSND_SAMPLE_LE); +#endif + return format; +} diff --git a/utils/wxMMedia/sndmulaw.h b/utils/wxMMedia/sndmulaw.h new file mode 100644 index 0000000000..840567462a --- /dev/null +++ b/utils/wxMMedia/sndmulaw.h @@ -0,0 +1,28 @@ +#ifndef __MEDIA_SNDMULAW_H__ +#define __MEDIA_SNDMULAW_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "sndfrmt.h" + +class wxSoundMulawCodec : public wxSoundCodec { + DECLARE_DYNAMIC_CLASS(wxSoundMulawCodec) + public: + wxSoundMulawCodec(); + virtual ~wxSoundMulawCodec(); + + void SetSampleRate(int srate) { m_srate = srate; } + + size_t GetByteRate() const; + wxSoundDataFormat GetPreferredFormat(int codec = 0) const; + + void Decode(); + void Encode(); + + protected: + int m_srate; +}; + +#endif diff --git a/utils/wxMMedia/sndpcm.cpp b/utils/wxMMedia/sndpcm.cpp new file mode 100644 index 0000000000..a1c5be0cf0 --- /dev/null +++ b/utils/wxMMedia/sndpcm.cpp @@ -0,0 +1,216 @@ +#ifdef __GNUG__ +#pragma implementation "sndpcm.h" +#endif +#include "sndsnd.h" +#include "sndpcm.h" +#include + +#define WX_BIG_ENDIAN 0 + +wxSoundPcmCodec::wxSoundPcmCodec() + : wxSoundCodec() +{ + m_orig_format.SetCodecCreate(FALSE); + m_orig_format.SetCodecNo(1); + m_char_bool = FALSE; +} + +wxSoundPcmCodec::~wxSoundPcmCodec() +{ +} + +size_t wxSoundPcmCodec::GetByteRate() const +{ + return (m_orig_format.GetBps()/8)* + m_orig_format.GetSampleRate()* + m_orig_format.GetChannels(); +} + +wxSoundDataFormat wxSoundPcmCodec::GetPreferredFormat(int codec) const +{ + wxSoundDataFormat prefFormat; + + prefFormat = m_orig_format; + prefFormat.SetCodecNo(WXSOUND_PCM); + return prefFormat; +} + +// --------------------------------------------------------------------------- +// Main part of the decoder +// --------------------------------------------------------------------------- + +void wxSoundPcmCodec::Decode() +{ + InitMode(DECODING); + if (m_io_format == m_orig_format) { + CopyToOutput(); + ExitMode(); + return; + } + + // Swap bytes + switch (m_io_format.GetBps()) { + case 8: + InputSign8(); + break; + case 16: + InputSwapAndSign16(); + break; + case 32: + case 64: + default: + break; + } + ExitMode(); +} + +// --------------------------------------------------------------------------- +// Change the sign of a 8-bit sample. + +#define GET() (m_in_sound->GetChar()) +#define PUT(c) (m_out_sound->PutChar(c)) +#define OUT_ERROR() (out->LastError() == wxStream_NOERROR) +#define IN_ERROR() (in->LastError() == wxStream_NOERROR) + +void wxSoundPcmCodec::InputSign8() +{ + unsigned char signer = 0; + wxStreamBase *in = m_out_sound->Stream(), *out = m_in_sound->Stream(); + + if (m_io_format.GetSign() != m_orig_format.GetSign()) + signer = 128; + + while (IN_ERROR() && OUT_ERROR()) + PUT(GET() + signer); + +} + +// --------------------------------------------------------------------------- +// Swap bytes and change the sign of a 16-bit sample. + +void wxSoundPcmCodec::InputSwapAndSign16() +{ + unsigned short signer1 = 0, signer2 = 0; + wxStreamBase *in = m_out_sound->Stream(), *out = m_in_sound->Stream(); + bool swap = (m_io_format.GetByteOrder() != m_orig_format.GetByteOrder()); + char temp; + + if (m_io_format.GetSign() != m_orig_format.GetSign()) { + if (m_io_format.GetByteOrder() == wxSND_SAMPLE_LE) + signer2 = 0x80; + else + signer1 = 0x80; + } + + if (swap) { + while (IN_ERROR() && OUT_ERROR()) { + temp = GET() ^ signer1; + PUT(GET() ^ signer2); + if (OUT_ERROR()) { + m_char_bool = TRUE; + m_char_stack = temp; + break; + } + PUT(temp); + } + } else { + while (IN_ERROR() && OUT_ERROR()) { + PUT(GET() ^ signer1); + if (OUT_ERROR()) { + m_char_bool = TRUE; + m_char_stack = temp; + break; + } + PUT(GET() ^ signer2); + } + } +} + +// --------------------------------------------------------------------------- +// Encoder part. +// --------------------------------------------------------------------------- + +void wxSoundPcmCodec::OutputSign8() +{ + wxStreamBase *in = m_out_sound->Stream(), *out = m_in_sound->Stream(); + unsigned char signer = 0; + + if (m_io_format.GetSign() != m_orig_format.GetSign()) + signer = 128; + + while (IN_ERROR() && OUT_ERROR()) + PUT((char)(GET() + signer)); +} + +// --------------------------------------------------------------------------- + +void wxSoundPcmCodec::OutputSwapAndSign16() +{ + bool swap = (m_io_format.GetByteOrder() != m_orig_format.GetByteOrder()); + unsigned short signer1 = 0, signer2 = 0; + char temp; + wxStreamBase *in = m_out_sound->Stream(), *out = m_in_sound->Stream(); + + if (m_char_bool) { + PUT(GET()); + PUT(m_char_stack); + m_char_bool = FALSE; + } + + if (m_io_format.GetSign() != m_orig_format.GetSign()) + if (m_io_format.GetByteOrder() == wxSND_SAMPLE_LE) + signer1 = 0x80; + else + signer2 = 0x80; + + if (swap) { + while (IN_ERROR()) { + temp = GET(); + PUT(GET() ^ signer1); + if (OUT_ERROR()) { + m_char_stack = temp ^ signer2; + m_char_bool = TRUE; + break; + } + PUT(temp ^ signer2); + } + } else { + while (IN_ERROR()) { + PUT(GET() ^ signer1); + if (!OUT_ERROR()) { + m_char_stack = GET() ^ signer2; + m_char_bool = TRUE; + break; + } + PUT(GET() ^ signer2); + } + } + +} + +// --------------------------------------------------------------------------- + +void wxSoundPcmCodec::Encode() +{ + InitMode(ENCODING); + if (m_io_format == m_orig_format) { + CopyToOutput(); + ExitMode(); + return; + } + + // Swap bytes + switch (m_io_format.GetBps()) { + case 8: + OutputSign8(); + break; + case 16: + OutputSwapAndSign16(); + break; + case 32: + case 64: + default: + break; + } + ExitMode(); +} diff --git a/utils/wxMMedia/sndpcm.h b/utils/wxMMedia/sndpcm.h new file mode 100644 index 0000000000..4c464dda21 --- /dev/null +++ b/utils/wxMMedia/sndpcm.h @@ -0,0 +1,39 @@ +#ifndef __SNDPCM_H__ +#define __SNDPCM_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "sndfrmt.h" + +class wxSoundPcmCodec : public wxSoundCodec { + DECLARE_DYNAMIC_CLASS(wxSoundPcmCodec) + public: + wxSoundPcmCodec(); + virtual ~wxSoundPcmCodec(); + + void SetSampleRate(int srate) { m_orig_format.SetSampleRate(srate); } + void SetBits(int bits) { m_orig_format.SetBps(bits); } + void SetByteOrder(int order) { m_orig_format.SetByteOrder(order); } + void SetSign(int sample_sign) { m_orig_format.SetSign(sample_sign); } + + size_t GetByteRate() const; + wxSoundDataFormat GetPreferredFormat(int codec = 0) const; + + void Decode(); + void Encode(); + + protected: + void InputSign8(); + void InputSwapAndSign16(); + void OutputSign8(); + void OutputSwapAndSign16(); + + protected: + wxSoundDataFormat m_orig_format; + char m_char_stack; + bool m_char_bool; +}; + +#endif diff --git a/utils/wxMMedia/sndsnd.cpp b/utils/wxMMedia/sndsnd.cpp new file mode 100644 index 0000000000..3422b7249f --- /dev/null +++ b/utils/wxMMedia/sndsnd.cpp @@ -0,0 +1,264 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndsnd.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndsnd.h" +#endif +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "sndsnd.h" +#include "sndfrmt.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#define PROCESS_EVENT() wxYield() +// #define PROCESS_EVENT() + +// ---------------------------------------------------------------------------- +// wxSndBuffer: base sound buffer class +// ---------------------------------------------------------------------------- + + +wxSndBuffer::wxSndBuffer() + : m_sndmode(wxSND_OUTPUT), m_sndflags(0), m_sndoutput(NULL), m_sndcodec(NULL) +{ +} + +wxSndBuffer::~wxSndBuffer() +{ +} + +void wxSndBuffer::Set(wxSndFlags flags) +{ + m_sndflags |= flags; + + if ((m_sndflags & wxSND_BUFAUTO) && (flags & wxSND_BUFREADY)) + m_sndoutput->QueueBuffer(*this); +} + +void wxSndBuffer::SetError(wxSndError error) +{ + if (error == wxSND_NOERROR) + Clear(wxSND_BUFERR); + else + Set(wxSND_BUFERR); + + m_snderror = error; +} + +wxSndError wxSndBuffer::GetError() +{ + if (IsNotSet(wxSND_BUFERR)) + return wxSND_NOERROR; + Clear(wxSND_BUFERR); + return m_snderror; +} + +void wxSndBuffer::OnPlayFinished() +{ +} + +void wxSndBuffer::OnBufferOutFinished() +{ +} + +void wxSndBuffer::OnBufferInFinished(char *WXUNUSED(iobuf), + wxUint32& WXUNUSED(size)) +{ +} + +bool wxSndBuffer::Wait() +{ + if (IsNotSet(wxSND_BUFLOCKED)) + return FALSE; + + while (IsSet(wxSND_BUFLOCKED)) + PROCESS_EVENT(); + + return IsNotSet(wxSND_BUFERR); +} + +void wxSndBuffer::HardLock() +{ + m_mutex.Lock(); +} + +void wxSndBuffer::HardUnlock() +{ + m_mutex.Unlock(); +} + +void wxSndBuffer::ChangeCodec(int no) +{ + wxDELETE(m_sndcodec); + + m_sndformat.SetCodecNo(no); + m_sndcodec = m_sndformat.GetCodec(); + m_sndcodec->SetIOBuffer(this); +} + +// ---------------------------------------------------------------------------- +// wxSndSimpleBuffer: the simplest sound buffer +// ---------------------------------------------------------------------------- + + +wxSndSimpleBuffer::wxSndSimpleBuffer(char *buffer, wxUint32 bufsize, + wxSndMode mode) + : wxSndBuffer() +{ + m_sndbuf = buffer; + m_sndsize = bufsize; + m_sndmode = mode; + + m_sndptr = 0; +} + +wxSndSimpleBuffer::~wxSndSimpleBuffer() +{ +} + +void wxSndSimpleBuffer::OnNeedOutputData(char *iobuf, wxUint32& size) +{ + char *buf = m_sndbuf + m_sndptr; + wxUint32 nbdata_left = m_sndsize - m_sndptr; + + if (m_sndptr >= m_sndsize) { + size = 0; + return; + } + + if (size > nbdata_left) + size = nbdata_left; + + m_sndptr += size; + + memcpy(iobuf, buf, size); +} + +void wxSndSimpleBuffer::OnBufferOutFinished() +{ + if (m_sndptr >= m_sndsize) + OnPlayFinished(); +} + +void wxSndSimpleBuffer::OnBufferInFinished(char *iobuf, wxUint32& size) +{ + char *raw_buf = m_sndbuf + m_sndptr; + wxUint32 data_left = m_sndsize - m_sndptr; + + if (!data_left) { + size = 0; + return; + } + + if (size > data_left) + size = data_left; + + memcpy(raw_buf, iobuf, size); + m_sndptr += size; +} + +void wxSndSimpleBuffer::SetData(char *buffer, wxUint32 bufsize, + wxSndMode mode) +{ + m_sndbuf = buffer; + m_sndsize = bufsize; + m_sndmode = mode; +} + +bool wxSndSimpleBuffer::RestartBuffer(wxSndMode mode) +{ + m_sndptr = 0; + return TRUE; +} + +wxUint32 wxSndSimpleBuffer::GetSize() const +{ + return m_sndsize; +} + +wxUint32 wxSndSimpleBuffer::Available() const +{ + return m_sndsize - m_sndptr; +} + +// ---------------------------------------------------------------------------- +// wxSound: base sound driver implementation +// ---------------------------------------------------------------------------- + +wxSound::wxSound() + : wxObject(), + m_lastbuf(NULL), m_sndcbk(NULL), m_snderror(wxSND_NOERROR) +{ + m_buffers.Clear(); +} + +wxSound::~wxSound() +{ + wxNode *node = m_buffers.First(); + + while (node) { + wxSndBuffer *buf = (wxSndBuffer *)node->Data(); + + buf->Clear(wxSND_BUFLOCKED); + } +} + +bool wxSound::QueueBuffer(wxSndBuffer& buf) +{ + if (buf.IsSet(wxSND_BUFLOCKED) || buf.IsNotSet(wxSND_BUFREADY)) + return FALSE; + + buf.Set(wxSND_BUFLOCKED); + buf.SetOutput(*this); + + m_buffers.Append(&buf); + return Wakeup(buf); +} + +bool wxSound::UnqueueBuffer(wxSndBuffer& buf) +{ + wxNode *node; + + if (buf.IsNotSet(wxSND_BUFLOCKED)) + return FALSE; + + node = m_buffers.Member(&buf); + if (!node) + return FALSE; + + StopBuffer(buf); + node = m_buffers.Member(&buf); + if (node) + delete node; + + return TRUE; +} + +void wxSound::Callback(wxSndCallback cbk) +{ + m_sndcbk = cbk; +} + +void wxSound::SetClientData(char *cdata) +{ + m_cdata = cdata; +} + +void wxSound::OnPlayBuffer(wxSndBuffer& buf) +{ + m_lastbuf = &buf; + if (m_sndcbk) + m_sndcbk(*this, buf, m_cdata); +} diff --git a/utils/wxMMedia/sndsnd.h b/utils/wxMMedia/sndsnd.h new file mode 100644 index 0000000000..9fae1a8794 --- /dev/null +++ b/utils/wxMMedia/sndsnd.h @@ -0,0 +1,275 @@ +/* Real -*- C++ -*- */ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndsnd.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +#ifndef __WX_SND_SOUND_H__ +#define __WX_SND_SOUND_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include +#include "sndfrmt.h" +#include "mmtype.h" + +class wxSound; +class wxSndBuffer; + +typedef enum { + wxSND_OUTPUT, + wxSND_INPUT, + wxSND_DUPLEX, + wxSND_OTHER_IO +} /// The possible sound output modes + wxSndMode; + +typedef enum { + wxSND_NOERROR = 0, + wxSND_NOCAPS, + wxSND_CANTOPEN, + wxSND_NOMEM, + wxSND_READERR, + wxSND_WRITEERR, + wxSND_CANTSET +} /// Sound errors + wxSndError; + +/// Sound callback +typedef void (*wxSndCallback)(wxSound&, wxSndBuffer&, char *); + +/// Sound flags +typedef wxUint16 wxSndFlags; + +/** @name Sound buffer flags */ +/// buffer ready +#define wxSND_BUFREADY 0x0001 +/// an error occured +#define wxSND_BUFERR 0x0002 +/// buffer is in use +#define wxSND_BUFLOCKED 0x0004 +/// the driver mustn't unqueue it +#define wxSND_KEEPQUEUED 0x0008 +/// automatic: when BUFREADY is set play the buffer +#define wxSND_BUFAUTO 0x0010 +/// +#define wxSND_UNFINISHED 0x0020 +/// buffer is nearly being unqueued +#define wxSND_UNQUEUEING 0x0040 +/// driver wants the buffer stop +#define wxSND_BUFSTOP 0x0080 +/// buffer will loop +#define wxSND_LOOP 0x0100 + +/** @name Sound data format */ +/// little endian +#define wxSND_SAMPLE_LE 0 +/// big endian +#define wxSND_SAMPLE_BE 1 +/// unsigned samples +#define wxSND_SAMPLE_UNSIGNED 0 +/// signed samples +#define wxSND_SAMPLE_SIGNED 1 + +/** @name wxSndBuffer + * @memo wxSndBuffer is the basic class for all the sound codec. + * @author Guilhem Lavaux + */ +class wxSndBuffer : public wxObject { + /// It is an abstract class + DECLARE_ABSTRACT_CLASS(wxSndBuffer) +protected: + wxMutex m_mutex; + /// output mode + wxSndMode m_sndmode; + /// last error + wxSndError m_snderror; + /// some flag + wxSndFlags m_sndflags; + /// last sound driver used + wxSound *m_sndoutput; + /// sound data format + wxSoundDataFormat m_sndformat; + /// current sound codec + wxSoundCodec *m_sndcodec; +public: + /** @name constructor and destructor */ + //@{ + /// Construct an uninitialized wxSndBuffer + wxSndBuffer(); + /// Destroy + virtual ~wxSndBuffer(); + //@} + + /** @name Functions returning the current state */ + //@{ + /// @return current mode + inline wxSndMode GetMode() const { return m_sndmode; } + /// @return sound data format + inline wxSoundDataFormat& GetFormat() { return m_sndformat; } + /// @return the size of the buffer + virtual wxUint32 GetSize() const = 0; + /// @return bytes left + virtual wxUint32 Available() const = 0; + + /** enable the specified flags + * @param flags + */ + void Set(wxSndFlags flags); + /** disable the specified flags + * @param flags + */ + inline void Clear(wxSndFlags flags) + { m_sndflags &= ~flags; } + /** Check if the specified flags is set + * @param flags + * @return TRUE if all flags is set + */ + inline bool IsSet(wxSndFlags flags) const + { return ((m_sndflags & flags) == flags); } + /** Check if the specified flags is not set + * @param flags + * @return TRUE if at least one flag is not set + */ + inline bool IsNotSet(wxSndFlags flags) const + { return ((m_sndflags & flags) != flags); } + /** Check if the buffer is currently being played + * @return TRUE + if the buffer is being played + */ + inline bool IsPlaying() const + { return IsSet(wxSND_BUFLOCKED); } + //@} + + /// + inline void SetOutput(wxSound& snd) + { m_sndoutput = &snd; } + /// + inline wxSoundCodec *GetCurrentCodec() const + { return m_sndcodec; } + /// + void HardLock(); + /// + void HardUnlock(); + + /// + wxSndError GetError(); + /// + void SetError(wxSndError err); + + /// + virtual bool Wait(); + /// + virtual bool RestartBuffer(wxSndMode mode) = 0; + /// + virtual bool Abort() { return TRUE; } + + /// + virtual void OnPlayFinished(); + + /** Data exchanging functions */ + //@{ + /// + virtual void OnNeedOutputData(char *io_buf, wxUint32& size) = 0; + /// + virtual void OnBufferOutFinished(); + /// + virtual void OnBufferInFinished(char *iobuf, wxUint32& size); + //@} + +protected: + void ChangeCodec(int no); +}; + +class wxSndSimpleBuffer : public wxSndBuffer { + DECLARE_DYNAMIC_CLASS(wxSndSimpleBuffer) +protected: + /// sound buffer + char *m_sndbuf; + /// size of the sound buffer + wxUint32 m_sndsize; + /// current position in the sound buffer + wxUint32 m_sndptr; +public: + wxSndSimpleBuffer(char *buffer = NULL, wxUint32 bufsize = 0, + wxSndMode mode = wxSND_OUTPUT); + virtual ~wxSndSimpleBuffer(); + + void SetData(char *buffer, wxUint32 bufsize, + wxSndMode mode = wxSND_OUTPUT); + inline void SetSoundFormat(const wxSoundDataFormat& format); + + void OnNeedOutputData(char *io_buf, wxUint32& size); + void OnNeedInputData(wxUint32& size); + + void OnBufferOutFinished(); + void OnBufferInFinished(char *iobuf, wxUint32& size); + + bool RestartBuffer(wxSndMode mode); + wxUint32 GetSize() const; + wxUint32 Available() const; +}; + +/// +class wxSound : public wxObject { + /// + DECLARE_ABSTRACT_CLASS(wxSound) +protected: + friend class wxFragmentBuffer; + + /// + wxSndBuffer *m_lastbuf; + /// + wxList m_buffers; + /// + wxSndCallback m_sndcbk; + /// + wxSndError m_snderror; + /// + char *m_cdata; +public: + /// + wxSound(); + /// + virtual ~wxSound(); + + /// + virtual bool QueueBuffer(wxSndBuffer& buf); + /// + virtual bool UnqueueBuffer(wxSndBuffer& buf); + /// + inline wxSndBuffer *LastBufferPlayed() + { return m_lastbuf; } + + /// + wxSndError GetError() { return m_snderror; } + + /// + void Callback(wxSndCallback cbk); + /// + void SetClientData(char *cdata); + /// + virtual void OnPlayBuffer(wxSndBuffer& buf); +protected: + /// + virtual bool Wakeup(wxSndBuffer& buf) = 0; + /// + virtual void StopBuffer(wxSndBuffer& buf) = 0; + + /// + virtual inline bool OnSetupDriver(wxSndBuffer& WXUNUSED(buf), + wxSndMode WXUNUSED(mode)) + { return TRUE; } +}; + +#endif diff --git a/utils/wxMMedia/snduss.cpp b/utils/wxMMedia/snduss.cpp new file mode 100644 index 0000000000..c98a741a12 --- /dev/null +++ b/utils/wxMMedia/snduss.cpp @@ -0,0 +1,268 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: snduss.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "snduss.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "wx/app.h" +#include "wx/utils.h" + +#define WXMMEDIA_INTERNAL +#include "snduss.h" +#include "sndfrmt.h" + +wxUssSound::wxUssSound() + : wxSound(), + m_srate(0), m_bps(0), m_stereo(0), + m_mode(wxSND_OTHER_IO), + m_stop_thrd(TRUE), m_sleeping(FALSE) +{ + m_fd = -1; + m_ussformat.SetCodecNo(WXSOUND_PCM); + m_ussformat.SetSign(wxSND_SAMPLE_SIGNED); + m_ussformat.SetByteOrder(wxSND_SAMPLE_LE); + + m_sndbuf = new wxStreamBuffer(wxStreamBuffer::read_write); + m_sndbuf->Flushable(FALSE); + m_sndbuf->Fixed(TRUE); +} + +wxUssSound::~wxUssSound() +{ + if (!m_stop_thrd) { + m_stop_thrd = TRUE; + if (m_sleeping) { + m_sleep_mtx.Lock(); + m_sleep_cond.Signal(); + m_sleep_mtx.Unlock(); + } + Join(); + } + + if (m_fd != -1) + close(m_fd); +} + +bool wxUssSound::Wakeup(wxSndBuffer& WXUNUSED(buf)) +{ + printf("Waking up (wxUssSound::Wakeup) ...\n"); + if (m_stop_thrd) { + m_stop_thrd = FALSE; + Entry(); +// wxThread::Create(); + } + + if (m_sleeping) { + m_sleep_mtx.Lock(); + m_sleep_cond.Signal(); + m_sleep_mtx.Unlock(); + } + + return TRUE; +} + +void wxUssSound::StopBuffer(wxSndBuffer& buf) +{ + buf.HardLock(); + buf.Set(wxSND_BUFSTOP); + buf.HardUnlock(); + while (buf.IsSet(wxSND_BUFSTOP)) + wxYield(); +// usleep(0); +} + +void wxUssSound::USS_Sleep() +{ + bool ret; + + printf("Asleeping ...\n"); + m_sleeping = TRUE; + m_sleep_mtx.Lock(); + ret = m_sleep_cond.Wait(m_sleep_mtx, 10, 0); + m_sleep_mtx.Unlock(); + m_sleeping = FALSE; + + printf("Waking up ...\n"); + if (!ret) + m_stop_thrd = TRUE; +} + +bool wxUssSound::DoInput(wxSndBuffer *buf) +{ + wxUint32 bufsize; + wxSoundCodec *codec = buf->GetFormat().GetCodec(); + + m_sndbuf->ResetBuffer(); + codec->SetInStream(m_sndbuf); + codec->InitIO(m_ussformat); + + bufsize = codec->Available(); + if (bufsize > m_max_bufsize) + bufsize = m_max_bufsize; + + if (!bufsize) { + buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY); + return false; + } + read(m_fd, m_sndbuf, bufsize); + codec->Encode(); + + return true; +} + +bool wxUssSound::DoOutput(wxSndBuffer *buf) +{ + wxSoundCodec *codec = buf->GetCurrentCodec(); + + m_sndbuf->ResetBuffer(); + codec->SetOutStream(m_sndbuf); + codec->InitIO(m_ussformat); + + if (!codec->Available()) { + buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY); + return false; + } + codec->Decode(); + write(m_fd, m_sndbuf, m_sndbuf->GetIntPosition()); + + // Well ... it's not accurate ! :-| + buf->OnBufferOutFinished(); + + return true; +} + +void *wxUssSound::Entry() +{ + wxNode *node; + wxSndBuffer *buf; + + while (!m_stop_thrd) { + node = m_buffers.First(); + if (!node) { + USS_Sleep(); + continue; + } + buf = (wxSndBuffer *)node->Data(); + if (!OnSetupDriver(*buf, buf->GetMode())) + continue; + + buf->HardLock(); + if (buf->IsSet(wxSND_BUFSTOP)) { + buf->HardUnlock(); + delete node; + continue; + } + switch(m_mode) { + case wxSND_INPUT: + if (!DoInput(buf)) + delete node; + break; + case wxSND_OUTPUT: + if (!DoOutput(buf)) + delete node; + break; + case wxSND_DUPLEX: + case wxSND_OTHER_IO: + break; + } + buf->HardUnlock(); + } + return NULL; +} + +bool wxUssSound::OnSetupDriver(wxSndBuffer& buf, wxSndMode WXUNUSED(mode)) +{ + wxSoundDataFormat format; + wxSoundCodec *codec; + + codec = buf.GetFormat().GetCodec(); + format = codec->GetPreferredFormat(WXSOUND_PCM); + + if ((format.GetSampleRate() != m_srate) || + (format.GetBps() != m_bps) || + (format.GetStereo() != m_stereo)) { + + if (!SetupSound(format.GetSampleRate(), format.GetBps(), + format.GetStereo())) { + m_buffers.DeleteObject(&buf); + buf.Clear(wxSND_BUFLOCKED | wxSND_BUFREADY); + buf.SetError(wxSND_CANTSET); + return false; + } + m_mode = wxSND_OTHER_IO; + } + + if (buf.GetMode() != m_mode) { + m_mode = buf.GetMode(); + return false; + } + + return true; +} + +wxUint32 wxUssSound::GetNbFragments() +{ + struct audio_buf_info frag_info; + + ioctl(m_fd, SNDCTL_DSP_GETOSPACE, &frag_info); + + return frag_info.fragstotal; +} + +wxUint32 wxUssSound::GetFragmentSize() +{ + return m_max_bufsize; +} + +bool wxUssSound::SetupSound(wxUint16 srate, wxUint8 bps, bool stereo) +{ + int tmp; + unsigned long tmp_ul; + + if (m_fd != -1) { + delete m_sndbuf; + fsync(m_fd); + close(m_fd); + } + + m_fd = open("/dev/dsp", O_RDWR); + + tmp = stereo; + if (ioctl(m_fd, SNDCTL_DSP_STEREO, &tmp) < 0) + return FALSE; + m_stereo = tmp; + + tmp_ul = srate; + if (ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp_ul) < 0) + return FALSE; + m_srate = tmp_ul; + + tmp = bps; + if (ioctl(m_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0) + return FALSE; + m_bps = tmp; + + ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &tmp); + m_max_bufsize = tmp; + m_sndbuf->SetBufferIO(m_max_bufsize); + + m_ussformat.SetBps(m_bps); + m_ussformat.SetChannels((m_stereo) ? 2 : 1); + m_ussformat.SetSampleRate(m_srate); + + return TRUE; +} diff --git a/utils/wxMMedia/snduss.h b/utils/wxMMedia/snduss.h new file mode 100644 index 0000000000..59569dd7c3 --- /dev/null +++ b/utils/wxMMedia/snduss.h @@ -0,0 +1,85 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: snduss.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_ussnd_H__ +#define __SND_ussnd_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#include +#include "sndsnd.h" +#include "sndfrag.h" +#include "sndfrmt.h" + +/// +class wxUssSound : public wxSound, public wxThread { + /// + DECLARE_DYNAMIC_CLASS(wxUssSound) +public: + wxUssSound(); + /// + virtual ~wxUssSound(); + + /// + void OnNeedBuffer(); +protected: + /// + virtual bool Wakeup(wxSndBuffer& buf); + /// + void USS_Sleep(); + /// + virtual void StopBuffer(wxSndBuffer& buf); + + /// + bool OnSetupDriver(wxSndBuffer& buf, wxSndMode mode); + + /// + bool SetupSound(wxUint16 srate, wxUint8 bps, bool stereo); + + /// + wxUint32 GetNbFragments(); + /// + wxUint32 GetFragmentSize(); + /// + void ThreadEntryPoint(); + +protected: + /// + wxUint16 m_srate; + /// + wxUint8 m_bps; + /// + wxUint32 m_max_bufsize; + /// + bool m_stereo; + /// + wxSndMode m_mode; + /// + wxSoundDataFormat m_ussformat; + /// + wxStreamBuffer *m_sndbuf; + /// + bool m_stop_thrd, m_sleeping; + /// Sound file descriptor. + int m_fd; + /// Thread sleep mutexes and conditions. + wxMutex m_sleep_mtx; + wxCondition m_sleep_cond; + + /// + bool DoInput(wxSndBuffer *buf); + bool DoOutput(wxSndBuffer *buf); + + /// + virtual void *Entry(); +}; + +#endif diff --git a/utils/wxMMedia/sndwav.cpp b/utils/wxMMedia/sndwav.cpp new file mode 100644 index 0000000000..ad6419147c --- /dev/null +++ b/utils/wxMMedia/sndwav.cpp @@ -0,0 +1,186 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndwav.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: February 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "sndwav.h" +#endif + +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include "sndwav.h" +#include "sndfrmt.h" +#include "sndpcm.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxSndWavCodec::wxSndWavCodec() + : wxSndFileCodec(), riff_codec() +{ + m_sndtime.hours = -1; +} + +wxSndWavCodec::wxSndWavCodec(wxOutputStream& s, bool seekable) + : wxSndFileCodec(s, seekable) +{ + if (!seekable) + CacheIO(); + riff_codec = wxRiffCodec(*m_ostream); + m_sndtime.hours = -1; +} + +wxSndWavCodec::wxSndWavCodec(wxInputStream& s, bool preload, bool seekable) + : wxSndFileCodec(s, preload, seekable) +{ + if (!seekable) + CacheIO(); + + riff_codec = wxRiffCodec(*m_istream); + m_sndtime.hours = -1; +} + +wxSndWavCodec::wxSndWavCodec(const wxString& fname) + : wxSndFileCodec(fname) +{ + riff_codec = wxRiffCodec(*m_istream); + m_sndtime.hours = -1; +} + +wxUint32 wxSndWavCodec::PrepareToPlay() +{ + if (!riff_codec.RiffReset(RIFF_READ)) + return 0; + + if (!riff_codec.FindChunk("RIFF", TRUE)) { + wxSndFileCodec::m_mmerror = wxMMFILE_INVALID; + return 0; + } + + char tmp_buf[5]; + riff_codec.ReadData(tmp_buf, 4); + tmp_buf[4] = 0; + if (wxString("WAVE") != tmp_buf) { + wxSndFileCodec::m_mmerror = wxMMFILE_INVALID; + return 0; + } + if (!riff_codec.FindChunk("fmt ", TRUE)) + return 0; + + riff_codec.Read16(wav_hdr.format); + riff_codec.Read16(wav_hdr.channels); + riff_codec.Read32(wav_hdr.sample_fq); + riff_codec.Read32(wav_hdr.byte_p_sec); + riff_codec.Read16(wav_hdr.byte_p_spl); + riff_codec.Read16(wav_hdr.bits_p_spl); + + if (!riff_codec.FindChunk("data")) + return 0; + + m_sndformat.SetSampleRate(wav_hdr.sample_fq); + m_sndformat.SetBps(wav_hdr.bits_p_spl); + m_sndformat.SetChannels(wav_hdr.channels); + m_sndmode = wxSND_OUTPUT; + ChangeCodec(wav_hdr.format); + + m_sndformat.SetSampleRate(wav_hdr.sample_fq); + m_sndformat.SetBps(wav_hdr.bits_p_spl); + m_sndformat.SetChannels(wav_hdr.channels); + + if (wav_hdr.format == WXSOUND_PCM) { + m_sndformat.SetSign(wxSND_SAMPLE_SIGNED); + m_sndformat.SetByteOrder(wxSND_SAMPLE_LE); + } + + wxUint32 sec1 = riff_codec.GetChunkLength() / wav_hdr.byte_p_sec, + sec2 = sec1 % 3600; + + m_sndtime.hours = sec1 / 3600; + m_sndtime.minutes = sec2 / 60; + m_sndtime.seconds = sec2 % 60; + + wxSndFileCodec::m_mmerror = wxMMFILE_NOERROR; + + return riff_codec.GetChunkLength(); +} + +wxSndWavCodec::~wxSndWavCodec() +{ +} + +bool wxSndWavCodec::OnNeedData(char *buf, wxUint32 size) +{ + return riff_codec.ReadData(buf, size); +} + +bool wxSndWavCodec::OnWriteData(char *buf, wxUint32 size) +{ + return riff_codec.WriteData(buf, size); +} + +bool wxSndWavCodec::PrepareToRecord(wxUint32 m_fsize) +{ + wxUint32 total_size; + + if (!riff_codec.RiffReset(RIFF_WRITE)) + return FALSE; + + total_size = 16 + sizeof(wav_hdr) + m_fsize; + + if (!riff_codec.CreateChunk("RIFF", total_size)) + return FALSE; + riff_codec.WriteData("WAVE", 4); + if (!riff_codec.CreateChunk("fmt ", sizeof(wav_hdr))) + return FALSE; + + wav_hdr.format = 1; // PCM_WAV_FORMAT + wav_hdr.channels = m_sndformat.GetChannels(); + wav_hdr.sample_fq = m_sndformat.GetSampleRate(); + wav_hdr.byte_p_spl = (m_sndformat.GetBps() / 8) * wav_hdr.channels; + wav_hdr.byte_p_sec = m_sndformat.GetCodec()->GetByteRate(); + wav_hdr.bits_p_spl = m_sndformat.GetBps(); + ChangeCodec(WXSOUND_PCM); + + if (wav_hdr.format == WXSOUND_PCM) { + m_sndformat.SetSign(wxSND_SAMPLE_SIGNED); + m_sndformat.SetByteOrder(wxSND_SAMPLE_LE); + } + + riff_codec.Write16(wav_hdr.format); + riff_codec.Write16(wav_hdr.channels); + riff_codec.Write32(wav_hdr.sample_fq); + riff_codec.Write32(wav_hdr.byte_p_sec); + riff_codec.Write16(wav_hdr.byte_p_spl); + riff_codec.Write16(wav_hdr.bits_p_spl); + + if (!riff_codec.CreateChunk("data", m_fsize)) + return FALSE; + return TRUE; +} + +void wxSndWavCodec::SetFile(wxInputStream& s, bool preload, bool seekable) +{ + wxMMediaFile::SetFile(s, preload, seekable); + if (!seekable) + CacheIO(); + + riff_codec.SetFile((seekable) ? s : *m_istream); +} + +void wxSndWavCodec::SetFile(wxOutputStream& s, bool seekable) +{ + wxMMediaFile::SetFile(s, seekable); + if (!seekable) + CacheIO(); + + riff_codec.SetFile((seekable) ? s : *m_ostream); +} diff --git a/utils/wxMMedia/sndwav.h b/utils/wxMMedia/sndwav.h new file mode 100644 index 0000000000..b442e34be1 --- /dev/null +++ b/utils/wxMMedia/sndwav.h @@ -0,0 +1,59 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndwav.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: February 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_wav_H__ +#define __SND_wav_H__ +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmriff.h" +#include "sndfile.h" + +/// +class wxSndWavCodec : public wxSndFileCodec { + /// + DECLARE_DYNAMIC_CLASS(wxSndWavCodec) +public: + /// + wxSndWavCodec(); + /// + wxSndWavCodec(wxInputStream& s, bool preload = FALSE, bool seekable = TRUE); + /// + wxSndWavCodec(wxOutputStream& s, bool seekable = TRUE); + /// + wxSndWavCodec(const wxString& fname); + /// + virtual ~wxSndWavCodec(); + + virtual bool OnNeedData(char *buf, wxUint32 size); + virtual bool OnWriteData(char *buf, wxUint32 size); + + virtual wxUint32 PrepareToPlay(); + virtual bool PrepareToRecord(wxUint32 file_size); + + virtual void SetFile(wxInputStream& s, bool preload = FALSE, + bool seekable = FALSE); + virtual void SetFile(wxOutputStream& s, + bool seekable = FALSE); + +protected: + wxRiffCodec riff_codec; + struct { + wxUint16 format; + wxUint16 channels; + wxUint32 sample_fq; + wxUint32 byte_p_sec; + wxUint16 byte_p_spl; + wxUint16 bits_p_spl; + } wav_hdr; +}; + +#endif diff --git a/utils/wxMMedia/sndwin.cpp b/utils/wxMMedia/sndwin.cpp new file mode 100644 index 0000000000..8161ed881f --- /dev/null +++ b/utils/wxMMedia/sndwin.cpp @@ -0,0 +1,384 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: sndwin.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include + +#define WXMMEDIA_INTERNAL +#include "sndwin.h" + +#define MMD_WIN_IO_BSIZE 16384 + +#include + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxSndWinFragment::wxSndWinFragment(wxSound& io_drv) + : wxFragmentBuffer(io_drv) +{ +} + +wxSndWinFragment::~wxSndWinFragment(void) +{ +} + +void wxSndWinFragment::AllocIOBuffer(void) +{ + wxWinSound *w_snd = (wxWinSound *) m_iodrv; + wxUint8 i; + + m_maxoq = 5; + m_maxiq = 5; + + m_lstoptrs = m_optrs = new wxFragBufPtr[m_maxoq]; + m_lstiptrs = m_iptrs = new wxFragBufPtr[m_maxiq]; + + for (i=0;iPrepareHeader(m_lstoptrs[i], wxSND_OUTPUT); + } + + for (i=0;iPrepareHeader(m_lstiptrs[i], wxSND_INPUT); + } +} + +void wxSndWinFragment::FreeIOBuffer(void) +{ + wxWinSound *w_snd = (wxWinSound *)m_iodrv; + wxUint8 i; + + if (!m_lstoptrs && !m_lstiptrs) + return; + + for (i=0;iUnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT); + delete m_lstoptrs[i].buffers; + } + + for (i=0;iUnprepareHeader(m_lstiptrs[i], wxSND_INPUT); + delete m_lstiptrs[i].buffers; + } + + delete[] m_lstoptrs; + delete[] m_lstiptrs; + + m_lstoptrs = m_lstiptrs = NULL; + m_maxoq = m_maxiq = 0; +} + +void wxSndWinFragment::WaitForAll() +{ + bool buf_busy = TRUE; + int i; + + m_dontq = TRUE; + + while (buf_busy) { + buf_busy = FALSE; + + for (i=0;iuser_data; + wxWinSound *w_snd = (wxWinSound *)m_iodrv; + MMRESULT result; + + switch (mode) { + case wxSND_INPUT: + result = waveInAddBuffer(w_snd->internal->devin_id, info->hdr, + sizeof(WAVEHDR)); + break; + case wxSND_OUTPUT: + result = waveOutWrite(w_snd->internal->devout_id, info->hdr, + sizeof(WAVEHDR)); + printf("WINOUT: result=%d\n", result); + break; + } + return TRUE; +} + +wxWinSound::wxWinSound(void) + : wxSound(), + fragments(*this) +{ + internal = new wxWinSoundInternal; + internal->devout_id = 0; + internal->devin_id = 0; + internal->sndWin = 0; + + wout_opened = FALSE; + win_opened = FALSE; + curr_o_srate = (wxUint32)-1; + curr_o_bps = (wxUint8)-1; + curr_o_stereo = (bool)-1; + curr_i_srate = (wxUint32)-1; + curr_i_bps = (wxUint8)-1; + curr_i_stereo = (bool)-1; +} + +wxWinSound::~wxWinSound(void) +{ + int i; + + fragments.WaitForAll(); + + if (wout_opened) + waveOutReset(internal->devout_id); + if (win_opened) + waveInReset(internal->devout_id); + + fragments.FreeIOBuffer(); + + if (wout_opened) + waveOutClose(internal->devout_id); + if (win_opened) + waveInClose(internal->devin_id); + + if (internal->sndWin) + ::DestroyWindow(internal->sndWin); + + delete internal; +} + +bool wxWinSound::Wakeup(wxSndBuffer& buf) +{ + if (!Reopen(buf, FALSE)) { + buf.Clear(wxSND_BUFLOCKED); + return FALSE; + } + + fragments.OnBufferFinished(NULL); + return TRUE; +} + +void wxWinSound::PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, + wxSndMode mode) +{ + wxSndWinInfo *info; + WAVEHDR *hdr; + + if ((mode == wxSND_INPUT && !win_opened) || + (mode == wxSND_OUTPUT && !wout_opened)) + return; + + info = new wxSndWinInfo; + + info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, frag.size); + info->h_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); + + info->data = (char *)GlobalLock(info->h_data); + hdr = info->hdr = (WAVEHDR *)GlobalLock(info->h_hdr); + + memset(hdr, 0, sizeof(*hdr)); + hdr->lpData = info->data; + hdr->dwBufferLength = frag.size; + hdr->dwUser = (DWORD)&frag; + hdr->dwFlags = WHDR_DONE; + + if (mode == wxSND_INPUT) { + MMRESULT result = waveInPrepareHeader(internal->devin_id, hdr, + sizeof(WAVEHDR)); + + printf("prepareIn = %d\n", result); + if (result != MMSYSERR_NOERROR) + wxExit(); + } else { + MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr, + sizeof(WAVEHDR)); + printf("prepareOut = %d\n", result); + if (result != MMSYSERR_NOERROR) + wxExit(); + } + + frag.user_data = (char *)info; + frag.data = info->data; +} + +void wxWinSound::UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, + wxSndMode mode) +{ + wxSndWinInfo *info = (wxSndWinInfo *)frag.user_data; + + if ((mode == wxSND_INPUT && !win_opened) || + (mode == wxSND_OUTPUT && !wout_opened)) + return; + + MMRESULT result; + + if (mode == wxSND_INPUT) { + result = waveInUnprepareHeader(internal->devin_id, info->hdr, sizeof(*info->hdr)); + } else { + result = waveOutUnprepareHeader(internal->devout_id, info->hdr, sizeof(*info->hdr)); + } + + printf("unprepare = %d\n", result); + + GlobalUnlock(info->h_hdr); + GlobalUnlock(info->h_data); + + GlobalFree(info->h_hdr); + GlobalFree(info->h_data); + + delete info; +} + +extern char wxCanvasClassName[]; + +LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case MM_WOM_DONE: { + wxWinSound *snd_drv = (wxWinSound *)GetWindowLong(hWnd, GWL_USERDATA); + WAVEHDR *hdr = (WAVEHDR *)lParam; + wxFragmentBuffer::wxFragBufPtr *buf = + (wxFragmentBuffer::wxFragBufPtr *)hdr->dwUser; + + // To be sure ... + hdr->dwFlags |= WHDR_DONE; + + snd_drv->fragments.OnBufferFinished(buf); + break; + } + case MM_WOM_OPEN: + printf("wave Open ack\n"); + break; + case MM_WOM_CLOSE: + printf("wave Close ack\n"); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return (LRESULT)0; +} + +void wxWinSound::StopBuffer(wxSndBuffer& buf) +{ + buf.HardLock(); + buf.Set(wxSND_BUFSTOP); + fragments.AbortBuffer(buf); + buf.HardUnlock(); + + while (buf.IsSet(wxSND_BUFSTOP)) + wxYield(); +} + +bool wxWinSound::Reopen(wxSndBuffer& buf, bool force) +{ + WAVEFORMATEX wformat; + + if ((buf.GetSampleRate() != curr_o_srate) || + (buf.GetBps() != curr_o_bps) || + (buf.GetStereo() != curr_o_stereo) || + (buf.GetMode() != curr_mode)) + force = TRUE; + + if (force) { + wxUint32 *curr_srate = + (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_srate : &curr_i_srate; + wxUint8 *curr_bps = + (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_bps : &curr_i_bps; + bool *curr_stereo = + (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_stereo : &curr_i_stereo; + + fragments.WaitForAll(); + fragments.FreeIOBuffer(); + + if (!internal->sndWin) { + FARPROC proc = MakeProcInstance((FARPROC)wxSoundHandlerWndProc, wxGetInstance()); + + internal->sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0, + 0, 0, 0, 0, NULL, (HMENU) NULL, + wxGetInstance(), 0); + + ::SetWindowLong(internal->sndWin, GWL_WNDPROC, + (LONG)proc); + ::SetWindowLong(internal->sndWin, GWL_USERDATA, (LONG) this); + } + + if (wout_opened) { + waveOutClose(internal->devout_id); + wout_opened = FALSE; + } + if (win_opened) { + waveInClose(internal->devin_id); + win_opened = FALSE; + } + + *curr_srate = buf.GetSampleRate(); + *curr_bps = buf.GetBps(); + *curr_stereo = buf.GetStereo(); + wformat.wFormatTag = WAVE_FORMAT_PCM; + wformat.nChannels = curr_o_stereo+1; + + wformat.nSamplesPerSec = curr_o_srate; + wformat.nBlockAlign = curr_o_bps / 8 * wformat.nChannels; + wformat.nAvgBytesPerSec = + wformat.nSamplesPerSec * wformat.nBlockAlign; + wformat.wBitsPerSample = curr_o_bps; + wformat.cbSize = 0; + + if (buf.GetMode() == wxSND_OUTPUT) { + MMRESULT result = waveOutOpen(&internal->devout_id, + WAVE_MAPPER, &wformat, + (DWORD)internal->sndWin, (DWORD)this, + CALLBACK_WINDOW); + if (result != MMSYSERR_NOERROR) + return FALSE; + internal->devin_id = 0; + wout_opened = TRUE; + curr_mode = wxSND_OUTPUT; + + fragments.AllocIOBuffer(); + } + else { + MMRESULT result = waveInOpen(&internal->devin_id, + WAVE_MAPPER, &wformat, + (DWORD)internal->sndWin, (DWORD)this, + CALLBACK_FUNCTION); + if (result != MMSYSERR_NOERROR) + return FALSE; + internal->devout_id = 0; + win_opened = TRUE; + curr_mode = wxSND_INPUT; + + fragments.AllocIOBuffer(); + } + } + return TRUE; +} diff --git a/utils/wxMMedia/sndwin.h b/utils/wxMMedia/sndwin.h new file mode 100644 index 0000000000..5ac3eb07a9 --- /dev/null +++ b/utils/wxMMedia/sndwin.h @@ -0,0 +1,108 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: sndwin.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __SND_win_H__ +#define __SND_win_H__ + +#include "sndsnd.h" +#include "sndfrag.h" + +#ifdef WXMMEDIA_INTERNAL +#include +#include +#include + +typedef struct wxWinSoundInternal { + HWAVEOUT devout_id; + HWAVEIN devin_id; + HWND sndWin; +} wxWinSoundInternal; + +typedef struct wxSndWinInfo { + HGLOBAL h_data, h_hdr; + + char *data; + WAVEHDR *hdr; +} wxSndWinInfo; + +#endif + +/** Sound buffer fragmenter: windows specific implementation + * @author Guilhem Lavaux + */ +class wxSndWinFragment : public wxFragmentBuffer { +public: + wxSndWinFragment(wxSound& io_drv); + virtual ~wxSndWinFragment(void); + + virtual void AllocIOBuffer(void); + virtual void FreeIOBuffer(void); + + virtual bool OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode); + + void WaitForAll(); +}; + +/// +class wxWinSound : public wxSound { + /// + DECLARE_DYNAMIC_CLASS(wxWinSound) +protected: + struct wxWinSoundInternal *internal; + + /// + bool wout_opened, win_opened; + /// + wxUint32 curr_o_srate, curr_i_srate; + /// + wxUint8 curr_o_bps, curr_i_bps; + /// + bool curr_o_stereo, curr_i_stereo; + /// + wxSndMode curr_mode; + + /// + wxSndWinFragment fragments; + +#ifdef WXMMEDIA_INTERNAL + /// + friend LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND win, + UINT message, + WPARAM wParam, LPARAM lParam); + +#endif + +public: + /// + wxWinSound(void); + /// + virtual ~wxWinSound(void); + + /// + void OnNeedBuffer(wxSndMode mode); + /// + void StopBuffer(wxSndBuffer& buf); +protected: + /// + virtual bool Wakeup(wxSndBuffer& buf); + + /// + bool Reopen(wxSndBuffer& buf, bool force); + + /// + friend class wxSndWinFragment; + + /// + void PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, wxSndMode mode); + /// + void UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, wxSndMode mode); +}; + +#endif diff --git a/utils/wxMMedia/ulaw.h b/utils/wxMMedia/ulaw.h new file mode 100644 index 0000000000..0ff8c0a3bd --- /dev/null +++ b/utils/wxMMedia/ulaw.h @@ -0,0 +1,69 @@ +static unsigned char ulaw_dsp[] = { + 3, 7, 11, 15, 19, 23, 27, 31, + 35, 39, 43, 47, 51, 55, 59, 63, + 66, 68, 70, 72, 74, 76, 78, 80, + 82, 84, 86, 88, 90, 92, 94, 96, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, + 113, 114, 114, 115, 115, 116, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 123, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 126, 126, 126, 126, + 126, 126, 126, 126, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 253, 249, 245, 241, 237, 233, 229, 225, + 221, 217, 213, 209, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 172, 170, 168, 166, 164, 162, 160, + 158, 157, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 147, 146, 145, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, + 139, 138, 138, 137, 137, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 133, 133, + 133, 133, 132, 132, 132, 132, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, +}; + +static unsigned char dsp_ulaw[] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, + 3, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 15, + 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, + 23, 24, 24, 25, 25, 26, 26, 27, + 27, 28, 28, 29, 29, 30, 30, 31, + 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 49, 51, 53, 55, 57, 59, 61, + 63, 66, 70, 74, 78, 84, 92, 104, + 254, 231, 219, 211, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 160, + 159, 159, 158, 158, 157, 157, 156, 156, + 155, 155, 154, 154, 153, 153, 152, 152, + 151, 151, 150, 150, 149, 149, 148, 148, + 147, 147, 146, 146, 145, 145, 144, 144, + 143, 143, 143, 143, 142, 142, 142, 142, + 141, 141, 141, 141, 140, 140, 140, 140, + 139, 139, 139, 139, 138, 138, 138, 138, + 137, 137, 137, 137, 136, 136, 136, 136, + 135, 135, 135, 135, 134, 134, 134, 134, + 133, 133, 133, 133, 132, 132, 132, 132, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 129, 128, 128, 128, 128, +}; diff --git a/utils/wxMMedia/vidbase.cpp b/utils/wxMMedia/vidbase.cpp new file mode 100644 index 0000000000..dbe8daeef4 --- /dev/null +++ b/utils/wxMMedia/vidbase.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: vidbdrv.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "vidbase.h" +#endif +#include +#include "vidbase.h" +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxVideoOutput::wxVideoOutput() + : wxWindow() +{ + dyn_size = TRUE; +} + +wxVideoOutput::wxVideoOutput(wxWindow *parent, const wxWindowID id, const wxPoint& position, + const wxSize& size, const long style, + const wxString& name) + : wxWindow(parent, id, position, size, style, name) +{ + dyn_size = TRUE; +} + +/// +wxVideoOutput::~wxVideoOutput() +{ +} + +wxVideoBaseDriver::wxVideoBaseDriver() + : wxMMediaFile() +{ +} + +wxVideoBaseDriver::wxVideoBaseDriver(wxInputStream& str, bool seekable) + : wxMMediaFile(str, FALSE, seekable) +{ +} + +wxVideoBaseDriver::wxVideoBaseDriver(const wxString& fname) + : wxMMediaFile(fname) +{ +} + +wxVideoBaseDriver::~wxVideoBaseDriver() +{ +} + +bool wxVideoBaseDriver::AttachOutput(wxVideoOutput& output) +{ + video_output = &output; + return TRUE; +} + +void wxVideoBaseDriver::DetachOutput() +{ + video_output = NULL; +} + +// Use an external frame for video output + +wxFrame *wxVideoCreateFrame(wxVideoBaseDriver *vid_drv) +{ + wxFrame *frame = new wxFrame(NULL, -1, "Video Output", wxDefaultPosition, wxSize(100, 100)); + wxVideoOutput *vid_out = new wxVideoOutput(frame, -1); + + vid_out->DynamicSize(TRUE); + vid_drv->AttachOutput(*vid_out); + frame->Layout(); + frame->Show(TRUE); + + return frame; +} diff --git a/utils/wxMMedia/vidbase.h b/utils/wxMMedia/vidbase.h new file mode 100644 index 0000000000..367b37389c --- /dev/null +++ b/utils/wxMMedia/vidbase.h @@ -0,0 +1,105 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: vidbase.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// CVS: $Id$ +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __VID_bdrv_H__ +#define __VID_bdrv_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmtype.h" +#include "mmfile.h" +#include "wx/string.h" +#include "wx/window.h" + +/// +typedef enum { + wxVIDEO_MSAVI, + wxVIDEO_MPEG, + wxVIDEO_QT, + wxVIDEO_GIF, + wxVIDEO_JMOV, + wxVIDEO_FLI, + wxVIDEO_IFF, + wxVIDEO_SGI, + wxVIDEO_MPEG2 +} /// + wxVideoType; + +/// +class wxVideoBaseDriver; +class wxVideoOutput : public wxWindow { + /// + DECLARE_DYNAMIC_CLASS(wxVideoOutput) +protected: + bool dyn_size; +public: + /// + wxVideoOutput(); + /// + wxVideoOutput(wxWindow *parent, const wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, const long style = 0, + const wxString& name = "video_output"); + /// + virtual ~wxVideoOutput(); + + /// + bool DynamicSize() { return dyn_size; } + /// + void DynamicSize(bool dyn) { dyn_size = dyn; } +}; + +/// +class wxVideoBaseDriver : public wxObject, public wxMMediaFile { + /// + DECLARE_ABSTRACT_CLASS(wxVideoBaseDriver) +protected: + wxVideoOutput *video_output; +public: + friend class wxVideoOutput; + + /// + wxVideoBaseDriver(); + /// + wxVideoBaseDriver(wxInputStream& str, bool seekable = FALSE); + /// + wxVideoBaseDriver(const wxString& fname); + /// + virtual ~wxVideoBaseDriver(); + + /// + virtual bool Pause() = 0; + /// + virtual bool Resume() = 0; + + /// + virtual bool SetVolume(wxUint8 vol) = 0; + /// + virtual bool Resize(wxUint16 w, wxUint16 h) = 0; + + /// + virtual bool IsCapable(wxVideoType WXUNUSED(v_type)) { return FALSE; } + + /// + virtual void OnFinished() {} + + /// + virtual bool AttachOutput(wxVideoOutput& output); + /// + virtual void DetachOutput(); +}; + +extern wxFrame *wxVideoCreateFrame(wxVideoBaseDriver *vid_drv); + + +#endif diff --git a/utils/wxMMedia/vidwin.cpp b/utils/wxMMedia/vidwin.cpp new file mode 100644 index 0000000000..a8e83b2dec --- /dev/null +++ b/utils/wxMMedia/vidwin.cpp @@ -0,0 +1,131 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: vidwin.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: February 1998 +// Updated: +// Copyright: (C) 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "vidwin.h" +#endif + +#if 0 +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif + +#define WXMMEDIA_INTERNAL +#include +#include +#include +#include "mmtype.h" +#include "mmfile.h" +#include "vidwin.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +wxVideoWindows::wxVideoWindows(void) +{ +} + +wxVideoWindows::wxVideoWindows(wxInputStream& str, bool seekable) + : wxVideoBaseDriver(str, seekable) +{ + OpenFile(GetCurrentFile()); +} + +wxVideoWindows::wxVideoWindows(const char *fname) + : wxVideoBaseDriver(fname) +{ + OpenFile(fname); +} + +wxVideoWindows::~wxVideoWindows(void) +{ + mciSendCommand(internal->dev_id, MCI_CLOSE, 0, 0); + + if (internal) + delete internal; +} + +void wxVideoWindows::OpenFile(const char *fname) +{ + MCI_DGV_OPEN_PARMS open_struct; + DWORD ret; + + internal = new VIDW_Internal; + + open_struct.lpstrDeviceType = "avivideo"; + open_struct.lpstrElementName = (LPSTR)fname; + open_struct.hWndParent = 0; + + ret = mciSendCommand(0, MCI_OPEN, + MCI_OPEN_ELEMENT|MCI_DGV_OPEN_PARENT|MCI_OPEN_TYPE|MCI_DGV_OPEN_32BIT, + (DWORD)(LPVOID)&open_struct); + internal->dev_id = open_struct.wDeviceID; +} + +bool wxVideoWindows::Pause(void) +{ + return (mciSendCommand(internal->dev_id, MCI_PAUSE, 0, 0) == 0); +} + +bool wxVideoWindows::Resume(void) +{ + return (mciSendCommand(internal->dev_id, MCI_PAUSE, 0, 0) == 0); +} + +bool wxVideoWindows::SetVolume(wxUint8 vol) +{ + return TRUE; +} + +bool wxVideoWindows::Resize(wxUint16 w, wxUint16 h) +{ + return TRUE; +} + +bool wxVideoWindows::IsCapable(wxVideoType v_type) +{ + return (v_type == wxVIDEO_MSAVI); +} + +bool wxVideoWindows::AttachOutput(wxVideoOutput& output) +{ + MCI_DGV_WINDOW_PARMS win_struct; + + if (!wxVideoBaseDriver::AttachOutput(output)) + return FALSE; + + win_struct.hWnd = (HWND)output.GetHWND(); + mciSendCommand(internal->dev_id, MCI_WINDOW, + MCI_DGV_WINDOW_HWND, (DWORD)(LPVOID)&win_struct); + return TRUE; +} + +void wxVideoWindows::DetachOutput(void) +{ + MCI_DGV_WINDOW_PARMS win_struct; + + wxVideoBaseDriver::DetachOutput(); + + win_struct.hWnd = 0; + mciSendCommand(internal->dev_id, MCI_WINDOW, + MCI_DGV_WINDOW_HWND, (DWORD)(LPVOID)&win_struct); +} + +bool wxVideoWindows::StartPlay(void) +{ + return (mciSendCommand(internal->dev_id, MCI_PLAY, 0, NULL) == 0); +} + +void wxVideoWindows::StopPlay(void) +{ + mciSendCommand(internal->dev_id, MCI_STOP, 0, NULL); +} diff --git a/utils/wxMMedia/vidwin.h b/utils/wxMMedia/vidwin.h new file mode 100644 index 0000000000..784d72a2c0 --- /dev/null +++ b/utils/wxMMedia/vidwin.h @@ -0,0 +1,62 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: vidwin.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: February 1998 +// Updated: +// Copyright: (C) 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __VID_windows_H__ +#define __VID_windows_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include "mmtype.h" +#include "mmfile.h" +#ifdef WX_PRECOMP +#include "wx/wxprec.h" +#else +#include "wx/wx.h" +#endif +#include "vidbase.h" + +#ifdef WXMMEDIA_INTERNAL +#include +#include + +typedef struct VIDW_Internal { + MCIDEVICEID dev_id; +} VIDW_Internal; +#endif + +class wxVideoWindows : public wxVideoBaseDriver { + DECLARE_DYNAMIC_CLASS(wxVideoWindows) +protected: + struct VIDW_Internal *internal; + + void OpenFile(const char *fname); +public: + wxVideoWindows(void); + wxVideoWindows(wxInputStream& str, bool seekable = FALSE); + wxVideoWindows(const char *fname); + virtual ~wxVideoWindows(void); + + virtual bool StartPlay(void); + virtual void StopPlay(void); + virtual bool Pause(void); + virtual bool Resume(void); + + virtual bool SetVolume(wxUint8 vol); + virtual bool Resize(wxUint16 w, wxUint16 h); + + virtual bool IsCapable(wxVideoType v_type); + + virtual bool AttachOutput(wxVideoOutput& output); + virtual void DetachOutput(void); +}; + +#endif diff --git a/utils/wxMMedia/vidxanm.cpp b/utils/wxMMedia/vidxanm.cpp new file mode 100644 index 0000000000..7a934c20e3 --- /dev/null +++ b/utils/wxMMedia/vidxanm.cpp @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////////// +// Name: vidxanm.cpp +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +//////////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "vidxanm.h" +#endif +#define WXMMEDIA_INTERNAL +#ifdef __XT__ +#define Uses_XLib +#define Uses_XtIntrinsic +#endif +#include "vidbase.h" +#include "vidxanm.h" +#ifdef WX_PRECOMP +#include "wx_prec.h" +#else +#include "wx/wx.h" +#endif +#include +#include +#ifdef __WXGTK__ +#include +#include +#endif + +wxVideoXANIM::wxVideoXANIM() + : wxVideoBaseDriver() +{ + internal = new wxXANIMinternal; + xanim_started = false; + paused = false; +} + +wxVideoXANIM::wxVideoXANIM(wxInputStream& str) + : wxVideoBaseDriver(str, false) +{ + internal = new wxXANIMinternal; + xanim_started = false; + paused = false; +} + +wxVideoXANIM::wxVideoXANIM(const wxString& fname) + : wxVideoBaseDriver(fname) +{ + internal = new wxXANIMinternal; + xanim_started = false; +} + +wxVideoXANIM::~wxVideoXANIM() +{ + if (xanim_started) + StopPlay(); + delete internal; +} + +bool wxVideoXANIM::StartPlay() +{ + if (!paused && xanim_started) + return true; + if (!video_output) + wxVideoCreateFrame(this); + + if (SendCommand(" ")) { + paused = false; + return true; + } + return false; +} + +bool wxVideoXANIM::Pause() +{ + if (!paused && SendCommand(" ")) { + paused = TRUE; + return TRUE; + } + return FALSE; +} + +bool wxVideoXANIM::Resume() +{ + if (paused && SendCommand(" ")) { + paused = FALSE; + return TRUE; + } + return FALSE; +} + +void wxVideoXANIM::StopPlay() +{ + if (!xanim_started) + return; + + SendCommand("q"); + + xanim_started = FALSE; + paused = FALSE; +} + +bool wxVideoXANIM::SetVolume(wxUint8 vol) +{ + if (vol > 100) + vol = 100; + + wxString str_vol("v%d", vol); + return SendCommand(str_vol.GetData()); +} + +bool wxVideoXANIM::Resize(wxUint16 WXUNUSED(w), wxUint16 WXUNUSED(h)) +{ + // Not implemented + // Actually, I think that we just need to resize the output window ... + return FALSE; +} + +bool wxVideoXANIM::IsCapable(wxVideoType v_type) +{ + if (v_type == wxVIDEO_MSAVI || v_type == wxVIDEO_MPEG || + v_type == wxVIDEO_QT || v_type == wxVIDEO_GIF || v_type == wxVIDEO_JMOV || + v_type == wxVIDEO_FLI || v_type == wxVIDEO_IFF || v_type == wxVIDEO_SGI) + return true; + else + return false; +} + +bool wxVideoXANIM::AttachOutput(wxVideoOutput& out) +{ + if (!wxVideoBaseDriver::AttachOutput(out)) + return false; + + return RestartXANIM(); +} + +void wxVideoXANIM::DetachOutput() +{ + SendCommand("q"); + xanim_started = false; + paused = false; + + wxVideoBaseDriver::DetachOutput(); +} + +bool wxVideoXANIM::SendCommand(const char *command, char **ret, + wxUint32 *size) +{ + if (!xanim_started) + if (!RestartXANIM()) + return false; + + // Send a command to XAnim through X11 Property + XChangeProperty(internal->xanim_dpy, internal->xanim_window, + internal->xanim_atom, + XA_STRING, 8, PropModeReplace, (unsigned char *)command, + strlen(command)); + XFlush(internal->xanim_dpy); + if (ret) { + int prop_format; + Atom prop_type; + unsigned long extra; + + XGetWindowProperty(internal->xanim_dpy, internal->xanim_window, + internal->xanim_ret, 0, 16, True, AnyPropertyType, + &prop_type, &prop_format, (unsigned long *)size, + &extra, (unsigned char **)ret); + } + return true; +} + +bool wxVideoXANIM::RestartXANIM() +{ + wxString xanim_command; + int ret; + Atom prop_type; + int prop_format; + unsigned long nitems; + unsigned long extra; + char prop[4]; + bool xanim_chg_size; + + if (!video_output || xanim_started || !GetCurrentFile()) + return false; + + // Check if we can change the size of the window dynamicly + xanim_chg_size = video_output->DynamicSize(); + // Get current display +#ifdef __XT__ + internal->xanim_dpy = wxAPP_DISPLAY; +#endif +#ifdef __WXGTK__ + internal->xanim_dpy = gdk_display; +#endif + // Get the window id +#ifdef __XT__ + internal->xanim_window = XtWindow(video_output->FWidget()); +#else + internal->xanim_window = + ((GdkWindowPrivate *)video_output->m_widget->window)->xwindow; +#endif + // Get the XANIM atom + internal->xanim_atom = XInternAtom(internal->xanim_dpy, + "XANIM_PROPERTY", False); + + // Build the command + xanim_command.sprintf(__XANIM_COMMAND__ " +W%d +Wp +f +B -Zr +q +Zpe +Ae " + "+Av70 %s %s", internal->xanim_window, + (xanim_chg_size == true) ? "+Sr" : "", + (const char *)GetCurrentFile()); + // Execute it + if (!wxExecute(xanim_command, false)) + return false; + + // Wait for XAnim to be ready + nitems = 0; + while (nitems == 0) { + ret = XGetWindowProperty(internal->xanim_dpy, internal->xanim_window, + internal->xanim_atom, + 0, 4, False, AnyPropertyType, &prop_type, + &prop_format, &nitems, &extra, + (unsigned char **)&prop); +// wxYield(); + } + + xanim_started = true; + + return true; +} diff --git a/utils/wxMMedia/vidxanm.h b/utils/wxMMedia/vidxanm.h new file mode 100644 index 0000000000..28d00989df --- /dev/null +++ b/utils/wxMMedia/vidxanm.h @@ -0,0 +1,69 @@ +// ///////////////////////////////////////////////////////////////////////////// +// Name: vidxanm.h +// Purpose: wxMMedia +// Author: Guilhem Lavaux +// Created: 1997 +// Updated: 1998 +// Copyright: (C) 1997, 1998, Guilhem Lavaux +// License: wxWindows license +// ///////////////////////////////////////////////////////////////////////////// +/* Real -*- C++ -*- */ +#ifndef __VID_xanim_H__ +#define __VID_xanim_H__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#if defined(WXMMEDIA_INTERNAL) && (defined(__X__) || defined(__WXGTK__)) +#include +#include +#endif + +#include "vidbase.h" + +#ifdef WXMMEDIA_INTERNAL +typedef struct wxXANIMinternal { + Display *xanim_dpy; + Window xanim_window; + Atom xanim_atom, xanim_ret; +} wxXANIMinternal; + +#ifndef __XANIM_COMMAND__ +#define __XANIM_COMMAND__ "/usr/X11R6/bin/xanim" +#endif +#endif + +class wxVideoXANIM : public wxVideoBaseDriver { + DECLARE_DYNAMIC_CLASS(wxVideoXANIM) +protected: + bool xanim_started, paused; + struct wxXANIMinternal *internal; +public: + wxVideoXANIM(); + wxVideoXANIM(wxInputStream& str); + wxVideoXANIM(const wxString& fname); + virtual ~wxVideoXANIM(); + + virtual bool StartPlay(); + virtual bool Pause(); + virtual bool Resume(); + virtual void StopPlay(); + + virtual bool SetVolume(wxUint8 vol); + virtual bool Resize(wxUint16 w, wxUint16 h); + + virtual bool IsCapable(wxVideoType v_type); + + virtual bool AttachOutput(wxVideoOutput& output); + virtual void DetachOutput(); + +protected: + /// + bool RestartXANIM(); + /// + bool SendCommand(const char *command, char **ret = NULL, + wxUint32 *size = NULL); +}; + +#endif diff --git a/utils/wxMMedia/wave.cpp b/utils/wxMMedia/wave.cpp new file mode 100644 index 0000000000..5f11afb1cc --- /dev/null +++ b/utils/wxMMedia/wave.cpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wave.cpp +// Purpose: wxWave class +// Author: Guilhem Lavaux / API by Julian Smart +// Modified by: +// Created: 04/23/98 +// RCS-ID: $Id$ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// +#ifdef __GNUG__ +#pragma implementation "wave.h" +#endif + +#include +#include "wave.h" + +wxWave::wxWave() +{ + m_wave = NULL; + m_iowave = NULL; +} + +wxWave::wxWave(const wxString& fileName, bool isResource = FALSE) +{ + Create(fileName, isResource); +} + +wxWave::~wxWave() +{ + Free(); +} + +bool wxWave::Create(const wxString& sFileName, bool isResource = FALSE) +{ + m_iowave = new wxFileInputStream(sFileName); + m_wave = new wxSndWavCodec(*m_iowave); + + return TRUE; +} + +bool wxWave::Play(bool async, bool looped) const +{ + if (!m_wave) + return FALSE; + + if (looped) + m_wave->Set(wxSND_LOOP); + if (!m_wave->StartPlay()); + return FALSE; + if (!async) + m_wave->Wait(); + + m_wave->Clear(wxSND_LOOP); + return TRUE; +} + +bool wxWave::Free() +{ + if (m_wave) { + delete m_wave; + delete m_iowave; + } + return TRUE; +} diff --git a/utils/wxMMedia/wave.h b/utils/wxMMedia/wave.h new file mode 100644 index 0000000000..b91edf96b7 --- /dev/null +++ b/utils/wxMMedia/wave.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wave.h +// Purpose: wxWave class +// Author: Julian Smart +// Modified by: Guilhem Lavaux for wxMMedia (02/05/1998) +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart and Markus Holzem +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef __WAVEH__ +#define __WAVEH__ + +#ifdef __GNUG__ +#pragma interface +#endif + +#include +#include +#include "sndwav.h" + +class wxWave : public wxObject +{ +public: + wxWave(); + wxWave(const wxString& fileName, bool isResource = FALSE); + ~wxWave(); + +public: + bool Create(const wxString& sFileName, bool isResource = FALSE); + bool IsOk() const { return (m_wave ? TRUE : FALSE); }; + bool Play(bool async = TRUE, bool looped = FALSE) const; + +protected: + bool Free(); + +protected: + wxInputStream *m_iowave; + wxSndWavCodec *m_wave; +}; + +#endif -- 2.45.2