

Apple Lossless Decoder in Coffeescript - jensnockert
https://github.com/ofmlabs/alac.js

======
tlrobinson
devongovett/jensnockert: what was your experience with using CoffeeScript for
such low level code? Did you need to consciously avoid certain CoffeeScript
features that could negatively impact performance?

~~~
devongovett
Overall positive, but as with any programming language, you have to be careful
sometimes. For example, the for loop in CoffeeScript can be slow if you aren't
careful:

    
    
        for i in [0...10]
          doSomething()
    

is slower than

    
    
        for i in [0...10] by 1
          doSomething()
    

because of the way it is compiled, so we always include the `by 1` as an
optimization.

Another one is that if you have a function and the last thing in that function
is a loop of some kind, CoffeeScript will try to return an array from that
function collecting the results of the loop. So we explicitly put a return
statement at the end of the function to avoid this and the performance
penalties.

There are probably a few more to be careful of, but overall performance
characteristics are similar to JS. I'm sure Jens has some thoughts too, but
overall I think it was a positive experience.

~~~
jbanon
This is the difference in compiled output for those examples:

    
    
      var i;
      
      for (i = 0; i < 10; i++) {
        doSomething();
      }
      
      for (i = 0; i < 10; i += 1) {
        doSomething();
      }
    

[http://jashkenas.github.com/coffee-
script/#try:for%20i%20in%...](http://jashkenas.github.com/coffee-
script/#try:for%20i%20in%20%5B0...10%5D%0A%20%20doSomething\(\)%0A%0Afor%20i%20in%20%5B0...10%5D%20by%201%0A%20%20doSomething\(\))

~~~
devongovett
Oops, I should have written it using a variable instead... i.e.

    
    
      for i in [0...test]
        doSomething()
    
      for i in [0...test] by 1
        doSomething()
    

compiles to:

    
    
      var i;
    
      for (i = 0; 0 <= test ? i < test : i > test; 0 <= test ? i++ : i--) {
        doSomething();
      }
    
      for (i = 0; i < test; i += 1) {
        doSomething();
      }
    

the latter one being much faster because it isn't testing the direction the
counter should be going all the time.

~~~
jashkenas
This is one of the grayer areas. After your experience writing this decoder
... would you prefer CoffeeScript to keep its loops that can go in either
direction, or would you prefer loops to always iterate upwards, and have to be
explicit if you'd like to count from "[100..1] by -1" ?

~~~
Stratoscope
I've programmed in dozens of languages, and I can't think of another one where
loops could automatically run either up or down depending on the start and end
values.

Not knowing CoffeeScript well, when I see this code:

n = -10 for i in [0...n] doSomething()

I'd expect it to call doSomething zero times. At least that's what I'd expect
in JavaScript or any of the other languages I've used.

~~~
jashkenas
I agree with you at least 40%, and that's originally how CoffeeScript behaved.
Would you still feel that way if you had explicitly written:

    
    
        for i in [10..0]
    

I've opened a ticket to discuss this further:
<https://github.com/jashkenas/coffee-script/issues/1952>

------
joncooper
I enjoyed reading this source, and will probably use your Buffer/Stream
classes in a project I'm working on. Thanks!

~~~
jensnockert
You're welcome!

------
devongovett
See a demo here: <http://codecs.ofmlabs.org/>

------
ditoa
Perhaps I am missing something obvious here (very possible as I do not work
with audio decoding) but the demo at <http://codecs.ofmlabs.org/> appears to
playback the MP3 (not tested the ALAC file yet) too quickly. The site reports
the MP3 as lasting 4:25 whereas manually downloading the track from the above
website Winamp says the track is 5:14 long and playback is noticeably slower.

Is this by design or a bug in the code (or a bug in Chrome (16-stable) that I
used to check out the demo site)?

~~~
devongovett
Well technically it is a missing feature in Chrome that we tried to work
around to varying degrees of success. The Chrome audio API has no way to
change the sample rate and uses whatever the native hardware sample rate is.
We didn't have time to finish implementing sample rate conversion in JS (but
it is coming) so we cheated a bit by dynamically loading a different file
based on some common hardware sample rates. It seems that sometimes Chrome
reports the sample rate wrong or something though, and we have seen this issue
at least once before and will be looking into it and reporting browser bugs
accordingly. Rest assured that this was just a hack, and real sample rate
conversion is JS is coming along soon! :)

------
jashkenas
@devongovett: Have you considered pushing the annotated source for this to
your "gh-pages" branch? It would make for a great read.

~~~
jensnockert
Would take quite some time annotating the source, not really our first
priority. (We have more codecs on our hitlist)

But if someone wants to do it, I think both me and @devongovett would be ready
to help out a bit.

(We usually hang out in #ofmlabs on freenode, if someone wants to speak with
us)

------
Andi
Stop wasting your time by rewriting existing JavaScript implementations in
other languages that compile to JavaScript!

~~~
jensnockert
Hm..? The only ALAC implementations we know of is the Apple one (in C++),
David Hammerton's one in C, and ours in Coffeescript.

------
swaits
Wow! Great work!

