File.hx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. //
  2. // WAV/AU Flash player with resampler
  3. //
  4. // Copyright (c) 2009, Anton Fedorov <datacompboy@call2ru.com>
  5. //
  6. /* This code is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 only, as
  8. * published by the Free Software Foundation.
  9. *
  10. * This code is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * version 2 for more details (a copy is included in the LICENSE file that
  14. * accompanied this code).
  15. */
  16. package fmt;
  17. // Generic file stream scanner interface
  18. interface IFile {
  19. var last: Bool;
  20. // Push data from audio stream to decoder
  21. function push(bytes: flash.utils.IDataInput, last:Bool): Void;
  22. // Require decoder to populate at least <samples> samples from audio stream
  23. function populate(samples: Int): Void;
  24. // Rewind on input stream to Pos, and return real pos we have seeked, or seeking to
  25. function seek(Pos: Float): Float;
  26. // Returns is stream ready to operate: header readed (1), not ready (0), error(-1)
  27. function ready(): Int;
  28. // Get sound samplerate is Hz
  29. function getRate(): Int;
  30. // Get sound channels
  31. function getChannels(): Int;
  32. // Set known full file length
  33. function setSize(size: Int): Void;
  34. // Get estimated sound length
  35. function getEtaLength(): Null<Float>;
  36. // Get loaded sound length
  37. function getLoadedLength(): Float;
  38. // Get count of complete samples available
  39. function samplesAvailable(): Int;
  40. // Get complete samples as array of channel samples
  41. function getSamples(): Array<Array<Float>>;
  42. }
  43. // File: generic stream file reader. Subclass it to define used sound decoder and headers
  44. class File implements IFile {
  45. public var last : Bool;
  46. var Buffer: flash.utils.ByteArray;
  47. var bufsize: Int;
  48. var rate : Int;
  49. var channels : Int;
  50. var sndDecoder : Null<Decoder>;
  51. var chunkSize : Int;
  52. var align : Int;
  53. var SoundBuffer: Array<Array<Float>>;
  54. var dataOff: Int;
  55. var dataSize : Null<Int>;
  56. var dataLen : Null<Float>;
  57. var Readed : Int;
  58. public function new() {
  59. Buffer = new flash.utils.ByteArray();
  60. bufsize = 0;
  61. rate = 0;
  62. channels = 0;
  63. chunkSize = 0;
  64. align = 0;
  65. Readed = 0;
  66. dataOff = 0;
  67. dataSize = 0;
  68. last = false;
  69. }
  70. // Initialize SoundBuffer after header readed
  71. private function init() {
  72. SoundBuffer = new Array<Array<Float>>();
  73. for(c in 0...channels)
  74. SoundBuffer.push( new Array<Float>() );
  75. }
  76. // Set known full file length
  77. public function setSize(size: Int): Void {
  78. dataSize = size;
  79. }
  80. // Get estimated sound length
  81. public function getEtaLength(): Null<Float> {
  82. if (rate==0 || chunkSize==0 || dataSize==0) return null;
  83. if (dataLen == null && dataSize > 0)
  84. dataLen = sndDecoder.decodeLength(Math.floor(dataSize/chunkSize))/rate;
  85. return dataLen;
  86. }
  87. // Get loaded sound length
  88. public function getLoadedLength(): Float {
  89. if (rate == 0 || chunkSize == 0 || sndDecoder==null)
  90. return 0.0;
  91. else
  92. return (bufsize-dataOff > dataLen)
  93. ? getEtaLength()
  94. : sndDecoder.decodeLength(Math.floor((bufsize-dataOff)/chunkSize)) / rate;
  95. }
  96. // Read file header
  97. public function readHeader() {
  98. return; // on raw file no header
  99. }
  100. // Push data from audio stream to decoder
  101. public function push(bytes: flash.utils.IDataInput, last:Bool): Void {
  102. if (ready() < 0) return; // Do not operate on error
  103. var avail = bytes.bytesAvailable;
  104. if (avail > 65536) avail = 65536;
  105. trace("Pushing "+avail+" bytes...");
  106. if (avail == 0) return;
  107. bytes.readBytes(Buffer, bufsize, avail);
  108. bufsize += avail;
  109. if (ready() == 0) readHeader();
  110. }
  111. // Require decoder to populate at least <samples> samples from audio stream
  112. public function populate(samples: Int): Void {
  113. if (ready() != 1) return;
  114. var i = Readed;
  115. var chk = 0;
  116. while(SoundBuffer[0].length < samples && bufsize - i >= chunkSize) {
  117. for(j in 0...channels) {
  118. sndDecoder.decode(Buffer, i, j, SoundBuffer[j], SoundBuffer[j].length);
  119. i += sndDecoder.sampleSize;
  120. }
  121. i += align;
  122. chk++;
  123. }
  124. Readed = i;
  125. last = (Readed-dataOff+chunkSize >= dataSize);
  126. if(chk>0) trace("Read "+chk+" chunks, last="+last+"; Readed="+Readed+"; dataSize="+dataSize+"; dataOff="+dataOff+"; chunkSize="+chunkSize);
  127. }
  128. // Rewind on input stream to Pos, and return real pos we have seeked, or seeking to
  129. public function seek(Pos: Float): Float {
  130. if (ready() != 1) return 0;
  131. var sample = Math.ceil( Pos * rate ); // Wanted sample number
  132. var chunk = sndDecoder.seek(Math.ceil( sample / sndDecoder.sampleLength )); // Wanted sample chunk
  133. var offset = chunk * chunkSize + dataOff; // Offset, where to seek
  134. if (offset > bufsize) // Round to maximal ready
  135. offset = Math.floor( (bufsize - dataOff) / chunkSize ) * chunkSize + dataOff;
  136. Readed = offset; // Seek to required offset
  137. sample = Math.ceil( (offset - dataOff) / chunkSize ) * sndDecoder.sampleLength; // Get final selected sample
  138. trace("Sync to Pos "+Pos+"; sample = "+sample+"; offset="+offset+"; res="+(sample/rate));
  139. return sample / rate;
  140. }
  141. // Returns is stream ready to operate: header readed (1), not ready (0), error(-1)
  142. public function ready(): Int {
  143. return -1;
  144. }
  145. // Get sound samplerate is Hz
  146. public function getRate(): Int {
  147. return rate;
  148. }
  149. // Get sound channels
  150. public function getChannels(): Int {
  151. return channels;
  152. }
  153. // Get count of complete samples available
  154. public function samplesAvailable(): Int {
  155. return SoundBuffer[0].length;
  156. }
  157. // Get complete samples as array of channel samples
  158. public function getSamples(): Array<Array<Float>> {
  159. var Ret = SoundBuffer;
  160. SoundBuffer = new Array<Array<Float>>();
  161. for(j in 0...channels)
  162. SoundBuffer.push(new Array<Float>());
  163. return Ret;
  164. }
  165. }