PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/org/xiph/system/AudioSink.hx

http://github.com/francois2metz/WavPlayer
Haxe | 233 lines | 188 code | 25 blank | 20 comment | 36 complexity | 9a9ed9692927ac232f7e83400d9cff1b MD5 | raw file
Possible License(s): GPL-3.0
  1. //
  2. // AudioSink
  3. // Generated sound player from FOGG project
  4. // http://bazaar.launchpad.net/~arkadini/fogg/trunk/files
  5. // Licensed under GPL
  6. //
  7. /* This code is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 only, as
  9. * published by the Free Software Foundation.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. */
  17. package org.xiph.system;
  18. //import org.xiph.system.Bytes;
  19. import flash.Vector;
  20. import flash.media.Sound;
  21. import flash.media.SoundChannel;
  22. import flash.media.SoundTransform;
  23. import flash.events.SampleDataEvent;
  24. class AudioSink extends flash.events.EventDispatcher {
  25. var buffer : Bytes;
  26. public var available : Int;
  27. var bufpos : Int;
  28. var triggered : Bool;
  29. var bufsize : Int;
  30. var trigger : Int;
  31. var bufstart : Int;
  32. var fill : Bool;
  33. var size : Int;
  34. public var pos : Float;
  35. public var volume(get_volume, set_volume): Float;
  36. public var pan(get_pan, set_pan): Float;
  37. public var soundTransform(get_soundTransform, set_soundTransform): SoundTransform;
  38. var s : Sound;
  39. var sch : SoundChannel;
  40. var schtr : SoundTransform;
  41. public function new(chunk_size : Int, fill = true, bufsize = 0, ?trigger : Int, ?st: SoundTransform) {
  42. super();
  43. size = chunk_size;
  44. this.fill = fill;
  45. this.bufsize = bufsize > 0 ? bufsize : 5*44100;
  46. this.trigger = trigger == null ? (bufsize > 0 ? bufsize : chunk_size) : trigger;
  47. triggered = false;
  48. trace("bufsize = "+this.bufsize+"; trigger="+this.trigger);
  49. buffer = new Bytes();
  50. available = 0;
  51. bufpos = 0;
  52. bufstart = 0;
  53. pos = 0.0;
  54. s = new Sound();
  55. s.addEventListener("sampleData", _data_cb);
  56. if (st == null) schtr = new SoundTransform();
  57. else schtr = st;
  58. sch = null;
  59. }
  60. public function set_volume(volume: Float): Float {
  61. this.schtr.volume=volume;
  62. this.soundTransform = this.soundTransform;
  63. return volume;
  64. }
  65. public function get_volume(): Float {
  66. return this.schtr.volume;
  67. }
  68. public function set_pan(pan: Float): Float {
  69. this.schtr.pan=pan;
  70. this.soundTransform = this.soundTransform;
  71. return this.schtr.pan;
  72. }
  73. public function get_pan(): Float {
  74. return this.schtr.pan;
  75. }
  76. public function set_soundTransform(st: SoundTransform): SoundTransform {
  77. this.schtr = st;
  78. if (this.sch!=null) {
  79. this.sch.soundTransform = this.schtr;
  80. }
  81. return this.schtr;
  82. }
  83. public function get_soundTransform(): SoundTransform {
  84. return this.schtr;
  85. }
  86. public function play(?position: Float) : Bool {
  87. if (sch!=null) return false;
  88. triggered = true;
  89. if (position!=null) {
  90. pos = position;
  91. var startpos = Math.ceil( pos*44100.0 ) - bufstart;
  92. trace("Playback from "+pos+" bufferpos="+startpos);
  93. if (startpos != bufpos) { // Need to seek in buffer
  94. trace("Need to seek to new buffer position: "+startpos+" / "+bufpos);
  95. if (startpos < 0) {
  96. trace("Need to seek in past, we can't");
  97. return false;
  98. }
  99. if (startpos > bufpos+available-size) {
  100. trace("Need to seek in future, we can't");
  101. return false;
  102. }
  103. var diff = bufpos - startpos;
  104. bufpos = startpos;
  105. available += diff;
  106. }
  107. pos = (bufstart + bufpos) / 44100.0;
  108. } else {
  109. bufstart += Math.ceil( pos * 44100 );
  110. }
  111. trace("playing");
  112. sch = s.play();
  113. sch.soundTransform = this.schtr;
  114. trace("SoundTransform volume = "+this.schtr.volume);
  115. sch.addEventListener(flash.events.Event.SOUND_COMPLETE, soundCompleteHandler);
  116. dispatchEvent(new PlayerEvent(PlayerEvent.PLAYING, pos));
  117. return true;
  118. }
  119. public function soundCompleteHandler(e:flash.events.Event):Void {
  120. sch = null;
  121. trace("Sound Complete: "+e);
  122. dispatchEvent(new PlayerEvent(PlayerEvent.STOPPED, 0.0));
  123. }
  124. public function pause() : Float {
  125. return stop(false);
  126. }
  127. public function stop(fireEvent: Bool = true) : Null<Float> {
  128. if (sch != null) {
  129. pos += sch.position / 1000.0;
  130. sch.stop();
  131. if (fireEvent)
  132. dispatchEvent(new PlayerEvent(PlayerEvent.STOPPED, pos));
  133. sch = null;
  134. }
  135. triggered = true;
  136. return pos;
  137. }
  138. function _data_cb(event : SampleDataEvent) : Void {
  139. trace("_data_cb "+event.position);
  140. var i : Int;
  141. var to_write : Int = available > size ? size : available;
  142. var missing = to_write < size ? size - to_write : 0;
  143. var bytes : Int = to_write * 8;
  144. if (to_write > 0) {
  145. event.data.writeBytes(buffer, bufpos * 8, bytes);
  146. trace("Bufstart="+bufstart+"; bufpos="+bufpos+"; avail="+available+"to_write = "+to_write);
  147. var bufend = available + bufpos;
  148. bufpos += to_write;
  149. available -= to_write;
  150. if (bufpos > bufsize) {
  151. var cutsize = bufpos - bufsize;
  152. bufpos = bufsize;
  153. bufstart += cutsize;
  154. System.bytescopy(buffer, cutsize*8, buffer, 0, (bufend-cutsize)*8);
  155. }
  156. }
  157. i = 0;
  158. if (missing > 0 && missing != size && fill) {
  159. trace("samples data underrun: " + missing);
  160. while (i < missing) {
  161. untyped {
  162. event.data.writeFloat(0.0);
  163. event.data.writeFloat(0.0);
  164. };
  165. i++;
  166. }
  167. } else if (missing > 0) {
  168. trace("not enough data, stopping");
  169. //stop();
  170. }
  171. }
  172. public function write(pcm : Array<Array<Float>>, index : Array<Int>,
  173. samples : Int, last : Bool = false) : Void {
  174. var i : Int;
  175. var end : Int;
  176. buffer.position = (available+bufpos) * 8; // 2 ch * 4 bytes per sample (float)
  177. if (pcm.length == 1) {
  178. // one channel
  179. var c = pcm[0];
  180. var s : Float;
  181. i = index[0];
  182. end = i + samples;
  183. while (i < samples) {
  184. s = c[i++];
  185. buffer.writeFloat(s);
  186. buffer.writeFloat(s);
  187. }
  188. } else if (pcm.length == 2) {
  189. // two channels
  190. var c1 = pcm[0];
  191. var c2 = pcm[1];
  192. i = index[0];
  193. var i2 = index[1];
  194. end = i + samples;
  195. while (i < end) {
  196. buffer.writeFloat(c1[i]);
  197. buffer.writeFloat(c2[i2++]);
  198. i++;
  199. }
  200. } else {
  201. throw "-EWRONGNUMCHANNELS";
  202. }
  203. available += samples;
  204. if (!triggered && (last || (trigger > 0 && available > trigger))) {
  205. play();
  206. }
  207. }
  208. }