Skip to content

Commit feee29d

Browse files
committed
20240224 -- first public version
1 parent 3475874 commit feee29d

File tree

7 files changed

+3536
-2
lines changed

7 files changed

+3536
-2
lines changed

CSW0.C

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
//@@@@ //@@@@@//@@ //@@//@@@@ //@@@@//@@@@@ //@@@@@@ -----------------------
2+
//@@//@@/@@ //@@/@@ //@@/@@//@@//@@//@@//@@/@@//@/@@/@ a companion of CSW2CDT
3+
//@@ //@@ //@@ //@@ //@@/@@ //@@//@@ //@@ turning WAV audio into
4+
//@@ //@@@@@//@@/@/@@//@@@@//@@ //@@//@@ //@@ CSW v1 files, coded by
5+
//@@ //@@/@@@@@@@/@@ //@@ //@@//@@ //@@ Cesar Nicolas-Gonzalez
6+
//@@//@@/@@ //@@/@@@/@@@/@@//@@//@@//@@//@@/@@ //@@ since 2020/05/31-09:50
7+
//@@@@ //@@@@@//@@ //@@/@@@@@@ //@@@@//@@@@@ //@@@@ ------------------------
8+
9+
#define MY_VERSION "20240224"
10+
#define MY_LICENSE "Copyright (C) 2020-2023 Cesar Nicolas-Gonzalez"
11+
12+
#define GPL_3_INFO \
13+
"This program comes with ABSOLUTELY NO WARRANTY; for more details" "\n" \
14+
"please see the GNU General Public License. This is free software" "\n" \
15+
"and you are welcome to redistribute it under certain conditions."
16+
17+
/* This notice applies to the source code of CSW2CDT and its binaries.
18+
19+
This program is free software: you can redistribute it and/or modify
20+
it under the terms of the GNU General Public License as published by
21+
the Free Software Foundation, either version 3 of the License, or
22+
(at your option) any later version.
23+
24+
This program is distributed in the hope that it will be useful,
25+
but WITHOUT ANY WARRANTY; without even the implied warranty of
26+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+
GNU General Public License for more details.
28+
29+
You should have received a copy of the GNU General Public License
30+
along with this program. If not, see <http://www.gnu.org/licenses/>.
31+
32+
Contact information: <mailto:cngsoft@gmail.com> */
33+
34+
#include <stdio.h> // fopen,printf...
35+
#include <stdlib.h> // atoll,malloc...
36+
#include <string.h> // memcmp,strcmp...
37+
38+
#define length(x) (sizeof(x)/sizeof*(x))
39+
unsigned char buffer[512]; FILE *fi,*fo;
40+
char *autosuffix(char *t,char *s,char *x) // return a valid path, with a new suffix if required
41+
{
42+
if (t) return t; else if (!s) return NULL; else if ((char*)buffer!=s) strcpy(buffer,s);
43+
if ((t=strrchr(buffer,'.'))&&(!(s=strrchr(buffer,
44+
#ifdef _WIN32
45+
'\\'
46+
#else
47+
'/'
48+
#endif
49+
))||t>s)) return strcpy(t,x),buffer; // override old suffix
50+
return strcat(buffer,x); // append new suffix
51+
}
52+
53+
// I/O file operations, buffering and Intel lil-endian integer logic -------- //
54+
55+
#define fread1(t,i) fread(t,1,i,fi)
56+
#define fwrite1(t,i) fwrite(t,1,i,fo)
57+
#define fput1(n) fputc(n,fo)
58+
int fput4(int i) { fput1(i); fput1(i>>8); fput1(i>>16); return fput1(i>>24); } // non-buffered!
59+
60+
unsigned char tsrc[1<<12],ttgt[1<<12]; int isrc=0,ilen=0,itgt=0; // I/O file buffers
61+
#define flush1() fwrite1(ttgt,itgt)
62+
int frecv1(void) { while (isrc>=ilen) if (isrc-=ilen,!(ilen=fread1(tsrc,sizeof(tsrc)))) return -1; return tsrc[isrc++]; }
63+
int frecv4(void) { int i=frecv1(); i|=frecv1()<<8; i|=frecv1()<<16; return i|(frecv1()<<24); }
64+
int fsend1(int i) { ttgt[itgt++]=i; if (itgt>=length(ttgt)) { if (!flush1()) return -1; itgt=0; } return i; }
65+
int fsend4(int i) { fsend1(i); fsend1(i>>8); fsend1(i>>16); return fsend1(i>>24); }
66+
67+
// the main procedure proper ------------------------------------------------ //
68+
69+
const char csw24b[]="Compressed Square Wave\032\001",ok_bytes[]="%d:%d bytes.\n",bad_target[]="error: cannot create target!\n";
70+
int plusatoi(char *s) { return atoi(*s=='+'?s+1:s); } // handle "+1234" as "1234"
71+
int readmmss(char *s) { int h=0,l=0,c; while ((c=*s++)>='0'&&c<='9') l=l*10+c-'0'; if (c==':') { h=l*60,l=0; while ((c=*s++)>='0'&&c<='9') l=l*10+c-'0'; } return c?-1:h+l; }
72+
73+
int main(int argc,char *argv[])
74+
{
75+
int h,i,j,k,l; char *si=NULL,*so=NULL;
76+
int flag_m=0,flag_e=0,flag_lr=0,flag_t=0,flag_n=0,filter_l=0,filter_h=0,hz,mmss_init=0,mmss_exit=-1;
77+
for (i=1;i<argc;++i)
78+
if (argv[i][0]=='-')
79+
if (argv[i][1])
80+
#define FETCH_INT(t,l,h) ((argv[i][++j]||(j=0,++i<argc))?t=plusatoi(&argv[i][j]),j=-1,t>=l&&t<h:0)
81+
for (j=0;++j>0&&i<argc&&argv[i][j];)
82+
switch (argv[i][j])
83+
{
84+
case 'f':
85+
if (!FETCH_INT(filter_l,0,96000))
86+
i=argc; // help!
87+
else if (++i>=argc||!FETCH_INT(filter_h,0,96000))
88+
i=argc; // help!
89+
if (filter_l&&filter_h&&filter_l>filter_h)
90+
k=filter_l,filter_l=filter_h,filter_h=k; // swap if L > H
91+
break;
92+
case 'm':
93+
if (!FETCH_INT(flag_m,-127,+127))
94+
i=argc; // help!
95+
break;
96+
case 'e':
97+
if (!FETCH_INT(flag_e,0,127))
98+
i=argc; // help!
99+
break;
100+
case 'l':
101+
flag_lr=-1;
102+
break;
103+
case 'r':
104+
flag_lr=+1;
105+
break;
106+
case 'n':
107+
flag_n=1;
108+
break;
109+
case 't':
110+
if (!FETCH_INT(flag_t,0,100))
111+
i=argc; // help!
112+
break;
113+
case '-':
114+
if (i+1<argc&&(j=readmmss(&argv[i][j+1]))>=0&&(mmss_init=j,(j=readmmss(argv[++i]))>=0))
115+
mmss_exit=j,j=-1;
116+
else
117+
i=argc; // help!
118+
break;
119+
case 'h':
120+
default:
121+
i=argc; // help!
122+
break;
123+
}
124+
else
125+
i=argc; // help!
126+
else if (!si)
127+
si=argv[i];
128+
else if (!so)
129+
so=argv[i];
130+
else i=argc; // help!
131+
if (i>argc||!si)
132+
return printf(
133+
"CSW0 " MY_VERSION " " MY_LICENSE "\n"
134+
"\n"
135+
"encoding from WAV to CSW:\n"
136+
"\tcsw0 [option..] source.wav [target.csw]\n"
137+
"\t-f L H\tenable pass-band filter, in Hz\n"
138+
"\t-m N\tset middle point between -127 and 127\n"
139+
"\t-e N\tset error margin between 0 and 127\n"
140+
"\t-l\tleft channel only\n"
141+
"\t-r\tright channel only\n"
142+
"\t-n\tnegative polarity\n"
143+
"\t--M1:S1 M2:S2\tclip from M1 min S1 sec to M2 min M2 sec\n"
144+
"decoding from CSW to WAV:\n"
145+
"\tcsw0 [option..] source.csw [target.wav]\n"
146+
"\t-t N\tset signal shape between 0 and 100 (square-triangle)\n"
147+
"\t-n\tnegative polarity\n"
148+
"\n" GPL_3_INFO "\n"
149+
),1;
150+
if (!(fi=fopen(si,"rb")))
151+
return fprintf(stderr,"error: cannot open source!\n"),1;
152+
if (*buffer=0,fread1(buffer,12),!memcmp(buffer,"RIFF",4)&&!memcmp(&buffer[8],"WAVE",4)) // encoding?
153+
{
154+
while (j=frecv4(),k=frecv4(),k>=0&&j!=0x20746D66) // "fmt "
155+
isrc+=(k+1)&~1; // RIFF even-padding
156+
if (k<16)
157+
return fclose(fi),fprintf(stderr,"error: source lacks header!\n"),1;
158+
int stereo=(frecv4()>>17)&1; // channels-1
159+
hz=frecv4();
160+
frecv4(); // actual byte rate...
161+
int datasize,byteskip=((frecv4()>>19)&3)-1,bytesize=byteskip+1; // bitdepth 8, 16 or 24 (!) -> byteskip = 0,1,2 (unused bytes per sample); bytesize = 1,2,3 (sample size in bytes)
162+
isrc+=((k+1)&~1)-16; // RIFF even-padding
163+
while (j=frecv4(),datasize=frecv4(),datasize>=0&&j!=0x61746164) // "data"
164+
isrc+=datasize;
165+
if (datasize<0)
166+
return fclose(fi),fprintf(stderr,"error: source lacks body!\n"),1;
167+
if (!(fo=fopen(autosuffix(so,si,".csw"),"wb")))
168+
return fclose(fi),fprintf(stderr,bad_target),1;
169+
fwrite1(csw24b,24);
170+
fsend4(hz*256+1+256*256*256); flag_m+=128;
171+
if (stereo) if (flag_lr<0) isrc-=bytesize; // avoid right channel
172+
if (mmss_init>0) { mmss_init*=(stereo+1)*bytesize*hz; isrc+=mmss_init,datasize-=mmss_init; } // source start...
173+
if (mmss_exit>0) { mmss_exit*=(stereo+1)*bytesize*hz; if (datasize>mmss_exit) datasize=mmss_exit; } // ...and end
174+
#define GETSAMPLE() (stereo? \
175+
byteskip?(datasize-=2*bytesize,isrc+=byteskip,i=frecv1()^128,isrc+=byteskip,i=(((frecv1()^128)+i)>>1)): \
176+
(datasize-=2,i=((frecv1()+frecv1())>>1)): \
177+
byteskip?(datasize-=bytesize,isrc+=byteskip,i=frecv1()^128): \
178+
(--datasize,i=frecv1()))
179+
#define SENDCHUNK do{ if (j) { if (j>255) fsend1(0),fsend4(j); else fsend1(j); j=0; } }while(0)
180+
GETSAMPLE(); fsend4(flag_n^(k=i>flag_m)); // store 1st signal!
181+
j=0; l=flag_m-flag_e; h=flag_m+flag_e;
182+
const float TWOPI=6.28318530717958647692528676655901;
183+
if (hz*filter_l>0)
184+
{
185+
if (hz*filter_h>0) // band-pass filter: H and L nonzero
186+
{
187+
int g=0; float h1=0,h2=0,high_alpha=1.0/(TWOPI*filter_l/hz+1.0),
188+
loww_alpha=(TWOPI*filter_h/hz)/(TWOPI*filter_h/hz+1.0);
189+
do
190+
{
191+
i-=flag_m; h2=high_alpha*(h2+i-g); g=i; // high-pass 1st
192+
h1=h1+loww_alpha*(h2-h1); // loww-pass 2nd
193+
if (k?(h1<=-flag_e):(h1>flag_e))
194+
{ SENDCHUNK; k=!k; }
195+
}
196+
while (++j,GETSAMPLE(),datasize>0&&ilen>0);
197+
}
198+
else // high-pass filter: H zero, L nonzero
199+
{
200+
int g=0; float hh=0,high_alpha=1.0/(TWOPI*filter_l/hz+1.0);
201+
do
202+
{
203+
i-=flag_m; hh=high_alpha*(hh+i-g); g=i; // high-pass
204+
if (k?(hh<=-flag_e):(hh>flag_e))
205+
{ SENDCHUNK; k=!k; }
206+
}
207+
while (++j,GETSAMPLE(),datasize>0&&ilen>0);
208+
}
209+
}
210+
else if (hz*filter_h>0) // low-pass filter: H nonzero, L zero
211+
{
212+
float hh=0,loww_alpha=(TWOPI*filter_h/hz)/(TWOPI*filter_h/hz+1.0);
213+
do
214+
{
215+
i-=flag_m; hh=hh+loww_alpha*(i-hh); // loww-pass
216+
if (k?(hh<=-flag_e):(hh>flag_e))
217+
{ SENDCHUNK; k=!k; }
218+
}
219+
while (++j,GETSAMPLE(),datasize>0&&ilen>0);
220+
}
221+
else // no filter
222+
{
223+
do
224+
{
225+
if (k?(i<=l):(i>h))
226+
{ SENDCHUNK; k=!k; }
227+
}
228+
while (++j,GETSAMPLE(),datasize>0&&ilen>0);
229+
}
230+
SENDCHUNK; flush1(); // flush!
231+
printf(ok_bytes,(int)ftell(fi),(int)ftell(fo));
232+
return fclose(fi),fclose(fo),0;
233+
}
234+
if (fread1(&buffer[12],(32-12))==(32-12)&&!memcmp(buffer,csw24b,24)) // decoding?
235+
{
236+
hz=buffer[25]+buffer[26]*256+(buffer[27]-1)*65536; k=((flag_n^buffer[28])&1)?32:224;
237+
if (!(fo=fopen(autosuffix(so,si,".wav"),"wb"))) // this call destroys `buffer`!
238+
return fclose(fi),fprintf(stderr,bad_target),1;
239+
fwrite1("RIFFFFFFWAVEfmt \020\000\000\000\001\000\001\000~~~~~~~~\001\000\010\000dataaaaa",44);
240+
int g=2+(hz-1)/1000; // i.e. almost 2 ms
241+
while ((i=frecv1())>=0)
242+
{
243+
k^=192; if (!i) i=frecv4();
244+
// long edges become flat at the end!
245+
l=0; if (i>g) l=i-g,i=g;
246+
// rising slope
247+
int g1=i*flag_t/200,g2=(i*flag_t+100)/200; i-=g1+g2;
248+
j=k-128; h=g1>>1; for (int n=1;n<=g1;++n) fsend1(128+(j*n+h)/g1);
249+
// ceiling, i.e. 128+96 / 128-96
250+
j=k; while (i>0) fsend1(j),--i;
251+
// falling slope
252+
j=k-128; h=g2>>1; for (int n=g2;n>=1;--n) fsend1(128+(j*n+h)/g2);
253+
// floor
254+
while (l) fsend1(128),--l;
255+
}
256+
if (itgt&1) fsend1(0); flush1(); // RIFF even-padding + flush!
257+
printf(ok_bytes,(int)ftell(fi),i=(int)ftell(fo));
258+
fseek(fo, 4,SEEK_SET); fput4(i-8); // file size-8 = chunk size+36
259+
fseek(fo,24,SEEK_SET); fput4(hz); fput4(hz); // clock + bandwidth
260+
fseek(fo,40,SEEK_SET); fput4(i-8-36); // chunk size = filesize-44
261+
return fclose(fi),fclose(fo),0;
262+
}
263+
return fprintf(stderr,"error: unknown source type!\n"),1;
264+
}

0 commit comments

Comments
 (0)