WAVCodec.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. MODULE WAVCodec; (** AUTHOR "MVT, PL"; PURPOSE "WAV audio format Codec"; *)
  2. IMPORT
  3. Codecs, SoundDevices, Streams, KernelLog,SYSTEM;
  4. CONST
  5. MAXBUF = 4096;
  6. TYPE
  7. Chunk = ARRAY 5 OF CHAR; (* type of wave header part *)
  8. (* Header of a wave file *)
  9. WaveHeader* = RECORD
  10. chunkRIFF: Chunk; (* must be "RIFF" *)
  11. chunkWAVE: Chunk; (* must be "WAVE" *)
  12. chunkfmt: Chunk; (* must be "fmt " *)
  13. waveFormatSize: LONGINT; (* must be 16 for PCM wave *)
  14. formatTag: INTEGER; (* must be 1 for PCM wave *)
  15. nofCh: INTEGER; (* number of channels *)
  16. sRate: LONGINT; (* sampling rate *)
  17. bRate: LONGINT; (* byte rate *)
  18. blockAlign: INTEGER; (* bytes per sample *)
  19. bitsPerSample: INTEGER; (* sampling resolution = bits per sample for 1 channel *)
  20. chunkdata: Chunk; (* must be "data" *)
  21. fileSize: LONGINT; (* size of the whole file minus 8 byte *)
  22. dataSize: LONGINT; (* size of PCM data in byte = file size minus header size *)
  23. END;
  24. (* Audio Wave PCM Encoder *)
  25. WAVEncoder* = OBJECT(Codecs.AudioEncoder)
  26. VAR
  27. out: Streams.Writer;
  28. h: WaveHeader;
  29. PROCEDURE Open*(out: Streams.Writer; sRate, sRes, nofCh: LONGINT; VAR res : WORD);
  30. BEGIN
  31. res := -1;
  32. IF out = NIL THEN
  33. KernelLog.String("WAVEncoder - Writer is NIL"); KernelLog.Ln;
  34. RETURN;
  35. END;
  36. SELF.out := out;
  37. (* Write wave header *)
  38. h.chunkRIFF[0] := "R"; h.chunkRIFF[1] := "I"; h.chunkRIFF[2] := "F"; h.chunkRIFF[3] := "F";
  39. out.Bytes(h.chunkRIFF, 0, 4);
  40. h.fileSize := SIZEOF(WaveHeader)-8; (* for wave file with zero-length sound - will be updated later *)
  41. WriteRawBELongInt(out, h.fileSize);
  42. h.chunkWAVE[0] := "W"; h.chunkWAVE[1] := "A"; h.chunkWAVE[2] := "V"; h.chunkWAVE[3] := "E";
  43. out.Bytes(h.chunkWAVE, 0, 4);
  44. h.chunkfmt[0] := "f"; h.chunkfmt[1] := "m"; h.chunkfmt[2] := "t"; h.chunkfmt[3] := " ";
  45. out.Bytes(h.chunkfmt, 0, 4);
  46. h.waveFormatSize := 16;
  47. WriteRawBELongInt(out, h.waveFormatSize);
  48. h.formatTag := 1;
  49. WriteRawBEInteger(out, h.formatTag);
  50. h.nofCh := SHORT(nofCh);
  51. WriteRawBEInteger(out, h.nofCh);
  52. h.sRate := sRate;
  53. WriteRawBELongInt(out, h.sRate);
  54. h.blockAlign := SHORT(nofCh * (sRes DIV 8));
  55. h.bRate := sRate * h.blockAlign;
  56. WriteRawBELongInt(out, h.bRate);
  57. WriteRawBEInteger(out, h.blockAlign);
  58. h.bitsPerSample := SHORT(sRes);
  59. WriteRawBEInteger(out, h.bitsPerSample);
  60. h.chunkdata[0] := "d"; h.chunkdata[1] := "a"; h.chunkdata[2] := "t"; h.chunkdata[3] := "a";
  61. out.Bytes(h.chunkdata, 0, 4);
  62. h.dataSize := 0; (* for wave file with zero-length sound - will be updated later *)
  63. WriteRawBELongInt(out, h.dataSize);
  64. out.Update;
  65. res := 0
  66. END Open;
  67. PROCEDURE Write*(buffer : SoundDevices.Buffer; VAR res : WORD);
  68. BEGIN
  69. out.Bytes(buffer.data^, 0, buffer.len);
  70. out.Update
  71. END Write;
  72. END WAVEncoder;
  73. (* Audio Wave PCM Decoder *)
  74. WAVDecoder* = OBJECT(Codecs.AudioDecoder)
  75. VAR in: Streams.Reader;
  76. h: WaveHeader;
  77. hasMoreBytes : BOOLEAN;
  78. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  79. VAR len, inLen: LONGINT; c: CHAR;
  80. BEGIN
  81. res := -1; inLen := 0;
  82. IF in = NIL THEN
  83. KernelLog.String("WAVDecoder - InputStream is NIL"); KernelLog.Ln;
  84. RETURN;
  85. END;
  86. SELF.in := in;
  87. (* Read header and check for correctness *)
  88. in.Bytes(h.chunkRIFF, 0, 4, inLen);
  89. IF (inLen # 4) OR (h.chunkRIFF # "RIFF") THEN
  90. KernelLog.String("WAVDecoder - RIFF header ID not found"); KernelLog.Ln;
  91. RETURN;
  92. END;
  93. ReadRawBELongInt(in, h.fileSize);
  94. in.Bytes(h.chunkWAVE, 0, 4, inLen);
  95. IF (inLen # 4) OR (h.chunkWAVE # "WAVE") THEN
  96. KernelLog.String("WAVDecoder - WAVE header ID not found"); KernelLog.Ln;
  97. RETURN;
  98. END;
  99. in.Bytes(h.chunkfmt, 0, 4, inLen);
  100. IF (inLen # 4) OR (h.chunkfmt # "fmt ") THEN
  101. KernelLog.String("WAVDecoder - fmt header ID not found"); KernelLog.Ln;
  102. RETURN;
  103. END;
  104. ReadRawBELongInt(in, h.waveFormatSize);
  105. IF (h.waveFormatSize < 16) THEN
  106. KernelLog.String("WAVDecoder - Wrong header size"); KernelLog.Ln;
  107. RETURN;
  108. END;
  109. in.RawInt(h.formatTag);
  110. IF (h.formatTag # 1) THEN
  111. KernelLog.String("WAVDecoder - Wrong wave format (must be PCM)"); KernelLog.Ln;
  112. RETURN;
  113. END;
  114. ReadRawBEInteger(in, h.nofCh);
  115. ReadRawBELongInt(in, h.sRate);
  116. ReadRawBELongInt(in, h.bRate);
  117. ReadRawBEInteger(in, h.blockAlign);
  118. ReadRawBEInteger(in, h.bitsPerSample);
  119. IF (h.blockAlign*h.sRate # h.bRate) OR (h.nofCh*(h.bitsPerSample DIV 8) # h.blockAlign) THEN
  120. KernelLog.String("WAVDecoder - Inconsistent header info"); KernelLog.Ln;
  121. RETURN;
  122. END;
  123. len := h.waveFormatSize - 16;
  124. WHILE len > 0 DO c := in.Get(); DEC(len) END;
  125. REPEAT
  126. in.Bytes(h.chunkdata, 0, 4, inLen);
  127. UNTIL (inLen = 4) & (h.chunkdata = "data") OR (in.Pos() >= (h.fileSize + 8));
  128. IF (inLen # 4) OR (h.chunkdata # "data") THEN
  129. KernelLog.String("WAVDecoder - data header ID not found"); KernelLog.Ln;
  130. KernelLog.String("res= "); KernelLog.Int(inLen, 0);
  131. KernelLog.String("h.chunkdata= "); KernelLog.String(h.chunkdata);
  132. RETURN;
  133. END;
  134. ReadRawBELongInt(in, h.dataSize);
  135. hasMoreBytes := TRUE;
  136. res := 0
  137. END Open;
  138. PROCEDURE HasMoreData*():BOOLEAN;
  139. BEGIN
  140. RETURN hasMoreBytes
  141. END HasMoreData;
  142. PROCEDURE GetAudioInfo*(VAR nofChannels, samplesPerSecond, bitsPerSample : LONGINT);
  143. BEGIN
  144. nofChannels := h.nofCh;
  145. bitsPerSample := h.bitsPerSample;
  146. samplesPerSecond := h.sRate
  147. END GetAudioInfo;
  148. (* Dumps part of the header *)
  149. PROCEDURE DumpHeader;
  150. BEGIN
  151. KernelLog.String("-- WAV Header Data --"); KernelLog.Ln;
  152. KernelLog.String("h.nofCh= "); KernelLog.Int(h.nofCh, 0); KernelLog.Ln;
  153. KernelLog.String("h.sRate= "); KernelLog.Int(h.sRate, 0); KernelLog.Ln;
  154. KernelLog.String("h.bitsPerSample= "); KernelLog.Int(h.bitsPerSample, 0); KernelLog.Ln;
  155. KernelLog.String("h.bRate= "); KernelLog.Int(h.bRate, 0); KernelLog.Ln;
  156. KernelLog.String("h.blockAlign= "); KernelLog.Int(h.blockAlign, 0); KernelLog.Ln;
  157. KernelLog.String("h.fileSize= "); KernelLog.Int(h.fileSize, 0);
  158. KernelLog.String("h.dataSize= "); KernelLog.Int(h.dataSize, 0)
  159. END DumpHeader;
  160. PROCEDURE CanSeek*() : BOOLEAN;
  161. BEGIN
  162. KernelLog.String("Not Implemented");
  163. RETURN FALSE;
  164. END CanSeek;
  165. PROCEDURE GetCurrentSample*() : LONGINT;
  166. BEGIN
  167. RETURN ENTIER((in.Pos() - (h.fileSize - h.dataSize)) / h.bRate * h.sRate)
  168. END GetCurrentSample;
  169. PROCEDURE GetTotalSamples*() : LONGINT;
  170. BEGIN
  171. RETURN ENTIER(h.dataSize / h.bRate * h.sRate)
  172. END GetTotalSamples;
  173. (* Returns the current time in 1/10 sec *)
  174. PROCEDURE GetCurrentTime*() : LONGINT;
  175. BEGIN
  176. RETURN ENTIER((in.Pos() - (h.fileSize - h.dataSize)) / h.bRate * 10)
  177. END GetCurrentTime;
  178. PROCEDURE SetStreamLength*(length : LONGINT);
  179. BEGIN
  180. h.fileSize := length-8;
  181. h.dataSize := length-SIZEOF(WaveHeader);
  182. END SetStreamLength;
  183. PROCEDURE SeekSample*(sample: LONGINT; goKeySample : BOOLEAN; VAR res : WORD);
  184. VAR seekType: LONGINT;
  185. BEGIN
  186. seekType := Codecs.SeekByte;
  187. (* in.Seek(seekType, h.fileSize - h.dataSize + ENTIER(sample / h.sRate * h.bRate), itemSize, res); *)
  188. in.SetPos(h.fileSize - h.dataSize + ENTIER(sample / h.sRate * h.bRate))
  189. END SeekSample;
  190. PROCEDURE SeekMillisecond*(millisecond : LONGINT; goKeySample : BOOLEAN; VAR res : WORD);
  191. BEGIN
  192. SeekSample(ENTIER(millisecond / 1000 * h.sRate), goKeySample, res)
  193. END SeekMillisecond;
  194. (** Prepare the next audio bytes not yet filled into a buffer *)
  195. PROCEDURE Next*;
  196. END Next;
  197. PROCEDURE FillBuffer*(buffer : SoundDevices.Buffer);
  198. BEGIN
  199. in.Bytes(buffer.data^, 0, LEN(buffer.data^), buffer.len);
  200. IF (in.res = Streams.EOF) OR (buffer.len < LEN(buffer.data)) THEN
  201. hasMoreBytes := FALSE;
  202. RETURN;
  203. END;
  204. END FillBuffer;
  205. END WAVDecoder;
  206. (* Audio PCM Decoder (WAV without header) *)
  207. PCMDecoder* = OBJECT(Codecs.AudioDecoder)
  208. VAR
  209. in: Streams.Reader;
  210. h : WaveHeader;
  211. hasMoreBytes : BOOLEAN;
  212. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  213. BEGIN
  214. res := -1;
  215. IF in = NIL THEN
  216. KernelLog.String("PCMDecoder - InputStream is NIL"); KernelLog.Ln;
  217. RETURN;
  218. END;
  219. SELF.in := in;
  220. hasMoreBytes := TRUE;
  221. res := 0
  222. END Open;
  223. PROCEDURE HasMoreData*():BOOLEAN;
  224. BEGIN
  225. RETURN hasMoreBytes
  226. END HasMoreData;
  227. PROCEDURE GetAudioInfo*(VAR nofChannels, samplesPerSecond, bitsPerSample : LONGINT);
  228. BEGIN
  229. nofChannels := h.nofCh;
  230. bitsPerSample := h.bitsPerSample;
  231. samplesPerSecond := h.sRate
  232. END GetAudioInfo;
  233. PROCEDURE SetAudioInfo*(nofChannels, samplesPerSecond, bitsPerSample : LONGINT);
  234. BEGIN
  235. h.nofCh := SHORT(nofChannels);
  236. h.bitsPerSample := SHORT(bitsPerSample);
  237. h.sRate := samplesPerSecond;
  238. (* calc the others *)
  239. h.bRate := h.nofCh * h.sRate * h.bitsPerSample DIV 8;
  240. h.blockAlign := h.nofCh * h.bitsPerSample DIV 8
  241. END SetAudioInfo;
  242. PROCEDURE CanSeek*() : BOOLEAN;
  243. BEGIN
  244. KernelLog.String("Not Implemented");
  245. RETURN FALSE;
  246. END CanSeek;
  247. PROCEDURE GetCurrentSample*() : LONGINT;
  248. BEGIN
  249. KernelLog.String("pi= ");
  250. RETURN ENTIER(8 * in.Pos() / h.bitsPerSample / h.nofCh)
  251. END GetCurrentSample;
  252. PROCEDURE GetTotalSamples*() : LONGINT;
  253. BEGIN
  254. KernelLog.String("pa= ");
  255. RETURN ENTIER(8 * h.dataSize / h.bitsPerSample / h.nofCh)
  256. END GetTotalSamples;
  257. (* Returns the current time in 1/10 sec *)
  258. PROCEDURE GetCurrentTime*() : LONGINT;
  259. BEGIN
  260. KernelLog.String("po= ");
  261. RETURN ENTIER(8 * in.Pos() / h.bitsPerSample / h.nofCh / h.sRate * 10)
  262. END GetCurrentTime;
  263. PROCEDURE SetStreamLength*(length : LONGINT);
  264. BEGIN
  265. h.fileSize := length+SIZEOF(WaveHeader)-8;
  266. h.dataSize := length
  267. END SetStreamLength;
  268. PROCEDURE SeekSample*(sample: LONGINT; goKeySample : BOOLEAN; VAR res : WORD);
  269. VAR seekType: LONGINT;
  270. BEGIN
  271. KernelLog.String("pu= "); KernelLog.Int(sample, 0);
  272. KernelLog.String("bi= "); KernelLog.Int(h.bitsPerSample, 0);
  273. seekType := Codecs.SeekByte;
  274. (* in.Seek(seekType, ENTIER(sample * h.bitsPerSample / 8 * h.nofCh), itemSize, res); *)
  275. in.SetPos(ENTIER(sample * h.bitsPerSample / 8 * h.nofCh))
  276. END SeekSample;
  277. PROCEDURE SeekMillisecond*(millisecond : LONGINT; goKeySample : BOOLEAN; VAR res : WORD);
  278. BEGIN
  279. SeekSample(ENTIER(millisecond / 1000 * h.sRate), goKeySample, res)
  280. END SeekMillisecond;
  281. (** Prepare the next audio bytes not yet filled into a buffer *)
  282. PROCEDURE Next*;
  283. END Next;
  284. PROCEDURE FillBuffer*(buffer : SoundDevices.Buffer);
  285. BEGIN
  286. in.Bytes(buffer.data^, 0, LEN(buffer.data^), buffer.len);
  287. IF (in.res = Streams.EOF) OR (buffer.len < LEN(buffer.data)) THEN
  288. hasMoreBytes := FALSE; KernelLog.String("BOOOOM!!");
  289. RETURN;
  290. END;
  291. END FillBuffer;
  292. END PCMDecoder;
  293. (* Routines for reading and writing numbers in Intel's big endian format *)
  294. PROCEDURE ReadRawBEInteger(VAR r: Streams.Reader; VAR value: INTEGER);
  295. BEGIN
  296. value := ORD(r.Get()) + 100H *ORD(r.Get());
  297. END ReadRawBEInteger;
  298. PROCEDURE ReadRawBELongInt(VAR r: Streams.Reader; VAR value: LONGINT);
  299. BEGIN
  300. value := LONG(ORD(r.Get())) + 100H * LONG(ORD(r.Get()))
  301. + 10000H * LONG(ORD(r.Get())) + 1000000H * LONG(ORD(r.Get()));
  302. END ReadRawBELongInt;
  303. PROCEDURE WriteRawBEInteger(VAR w: Streams.Writer; value: INTEGER);
  304. BEGIN
  305. w.Char(CHR(value MOD 100H));
  306. w.Char(CHR(value DIV 100H));
  307. END WriteRawBEInteger;
  308. PROCEDURE WriteRawBELongInt(VAR w: Streams.Writer; value: LONGINT);
  309. BEGIN
  310. w.Char(CHR(value MOD 100H));
  311. value := value DIV 100H;
  312. w.Char(CHR(value MOD 100H));
  313. value := value DIV 100H;
  314. w.Char(CHR(value MOD 100H));
  315. w.Char(CHR(value DIV 100H));
  316. END WriteRawBELongInt;
  317. (* -- Factories -- *)
  318. PROCEDURE EncoderFactory*() : Codecs.AudioEncoder;
  319. VAR p : WAVEncoder;
  320. BEGIN
  321. NEW(p);
  322. RETURN p
  323. END EncoderFactory;
  324. PROCEDURE DecoderFactory*() : Codecs.AudioDecoder;
  325. VAR p : WAVDecoder;
  326. BEGIN
  327. NEW(p);
  328. RETURN p
  329. END DecoderFactory;
  330. PROCEDURE PCMDecoderFactory*() : Codecs.AudioDecoder;
  331. VAR p : PCMDecoder;
  332. BEGIN
  333. NEW(p);
  334. RETURN p
  335. END PCMDecoderFactory
  336. END WAVCodec.
  337. ------------------------------------------------------------------------------
  338. System.Free WAVCodec;