/flash/flash-audio/src/com/ryanberdeen/audio/DiscontinuousSampleSource.as

http://echo-nest-remix.googlecode.com/ · ActionScript · 139 lines · 106 code · 24 blank · 9 comment · 17 complexity · a864c5b6f70c34cd62606bfe923018e5 MD5 · raw file

  1. /*
  2. * Copyright 2009 Ryan Berdeen. All rights reserved.
  3. * Distributed under the terms of the MIT License.
  4. * See accompanying file LICENSE.txt
  5. */
  6. package com.ryanberdeen.audio {
  7. import flash.media.Sound;
  8. import flash.utils.ByteArray;
  9. /**
  10. * Provides samples based on an arbitrary list of sample ranges.
  11. */
  12. public class DiscontinuousSampleSource implements ISampleSource {
  13. private var _sampleSource:ISampleSource;
  14. private var _sampleRanges:Array;
  15. private var _length:Number;
  16. private var extractionRangeIndex:int;
  17. private var extractionRange:SampleRange;
  18. private var extractionPosition:Number;
  19. private var startPosition:Number;
  20. private var finished:Boolean;
  21. private var positionRangeIndex:int;
  22. private var localPosition:Number;
  23. private var linearPosition:Number;
  24. public function set sampleSource(sampleSource:ISampleSource):void {
  25. _sampleSource = sampleSource;
  26. }
  27. public function set sampleRanges(sampleRanges:Array):void {
  28. _sampleRanges = sampleRanges;
  29. extractionRangeIndex = 0;
  30. extractionRange = _sampleRanges[extractionRangeIndex];
  31. extractionPosition = extractionRange.start;
  32. startPosition = 0;
  33. linearPosition = 0;
  34. localPosition = extractionPosition;
  35. positionRangeIndex = 0;
  36. _length = 0;
  37. for each (var sampleRange:SampleRange in _sampleRanges) {
  38. _length += sampleRange.length;
  39. }
  40. }
  41. public function extract(target:ByteArray, length:Number, startPosition:Number = -1):Number {
  42. if (startPosition != -1) {
  43. if (startPosition != this.startPosition) {
  44. var newPosition:Array = seek(this.startPosition, startPosition, extractionPosition, extractionRangeIndex);
  45. extractionPosition = newPosition[0];
  46. extractionRangeIndex = newPosition[1];
  47. extractionRange = _sampleRanges[extractionRangeIndex];
  48. }
  49. }
  50. var samplesRead:int = 0;
  51. while (!finished && samplesRead < length) {
  52. var samplesLeft:int = extractionRange.end - extractionPosition;
  53. var samplesToRead:int = Math.min(samplesLeft, length - samplesRead);
  54. _sampleSource.extract(target, samplesToRead, extractionPosition);
  55. samplesRead += samplesToRead;
  56. extractionPosition += samplesToRead;
  57. if (extractionPosition == extractionRange.end) {
  58. extractionRangeIndex++;
  59. if (extractionRangeIndex == _sampleRanges.length) {
  60. finished = true;
  61. }
  62. else {
  63. extractionRange = _sampleRanges[extractionRangeIndex];
  64. extractionPosition = extractionRange.start;
  65. }
  66. }
  67. }
  68. this.startPosition = startPosition + samplesRead;
  69. return samplesRead;
  70. }
  71. public function toSourcePosition(position:Number):Number {
  72. var result:Array = seek(linearPosition, position, localPosition, positionRangeIndex);
  73. linearPosition = position;
  74. localPosition = result[0];
  75. positionRangeIndex = result[1];
  76. return result[0];
  77. }
  78. private function seek(linearStart:Number, linearEnd:Number, sourcePosition:Number, index:int):Array {
  79. if (linearEnd < linearStart) {
  80. // TODO might be faster to seek backwards and then seek forwards
  81. linearStart = 0;
  82. index = 0;
  83. sourcePosition = _sampleRanges[index].start;
  84. }
  85. var distance:Number = linearEnd - linearStart;
  86. var range:SampleRange;
  87. var distanceLeft:Number;
  88. var samplesLeftThisRange:Number;
  89. var samplesAdvanced:Number = 0;
  90. while (samplesAdvanced < distance) {
  91. range = _sampleRanges[index];
  92. samplesLeftThisRange = range.end - sourcePosition;
  93. distanceLeft = distance - samplesAdvanced;
  94. if (samplesLeftThisRange > distanceLeft) {
  95. sourcePosition += distanceLeft;
  96. samplesAdvanced += distanceLeft;
  97. }
  98. else {
  99. index++;
  100. if (index < _sampleRanges.length) {
  101. sourcePosition = _sampleRanges[index].start;
  102. }
  103. samplesAdvanced += samplesLeftThisRange;
  104. }
  105. }
  106. return [sourcePosition, index];
  107. }
  108. public function get length():Number {
  109. return _length;
  110. }
  111. public function get rangeIndex():int {
  112. return positionRangeIndex;
  113. }
  114. }
  115. }