<< >>
justin = { main feed , music , code , askjf , pubkey };recent comments
search
Searching for 'xt' in (articles)... [back to index]

January 30, 2024
SOB 100k race report - I came to chew bubblegum and climb hills, and I was all out of bubblegum?

My last trail race was a bit over a year ago and apparently these experiences are some of the few I find worth documenting, so I'll bring the imaginary reader up to date on the the last year of running/hiking related activities/health/etc, even though my 2023-in-review post did some light quantification.

After Ray Miller I kept running and ran some road races in NY, including the Brooklyn Half, and a 5k a week later (when I wasn't fully recovered, which was also fun but probably too hard to soon). Later on in May I started having some leg nerve feelings, which ended up being caused by a herniated disc, so I had to cool it on the running for a bit. I started walking a lot. Pretty much any time I would normally bicycle somewhere, I'd walk instead. And as advised, I got a routine going of core strength exercises, and figured out how to continue my glute/hamstring PT. The gym, ugh. I think I read somewhere that gymnasiums were originally places where people would work out in the nude. Maybe the root was the greek word for nudity? anyway I digress. I find myself doing this in text messages too, saying way too much. Do I do it in person too and not notice it because there's no written record of it?

In the summer, Steve, Edward and I all signed up for the January 27, 2024 Sean O'Brien 50 miler. Edward and I ran this race in 2020, right before the pandemic, and joked about how covid would be nothing. When I signed up for the 2024 race, I wasn't running, did not know if I would be running by January, but I figured worst case I could try to power hike it.

I walked the NY Marathon in November (in 5:20 or so), which was a fantastic experience and I would recommend it to anybody who likes to walk. I took videos of a lot of the bands who played and then had a good Strava post which read as a tripadvisor review of the New York Music Festival -- too much walking! I should've posted those videos here. Maybe I still will. Let me know in the comments if you think that's a good idea.

A couple of weeks after the NY Marathon, I started running again, and worked up (with a covid-intermission) to a few 15-20 mile weeks, on top of 40-60 miles of walking. When I was running at my peak, the most miles per week I'd ever sustain was about 40, so I was feeling pretty good about the volume and time on my feet. Then, the week before the race, the SOB organizers sent out an email that mentioned you could change distances, and also that if you were running the 100k and you missed the 17 hour cutoff (or decided you wanted to bail), you could drop to the 50 miler during the race, at mile 43. So it became a fathomable thing -- sign up for the 100k, and if you're not feeling it at 43, just do 50. And not only that, if things go really poorly, it buys you another half hour for the 50 miler. Steve and I decided to do that.


(an old friend saw me off on my journey)

We drove to LA.


(this dog barked at me until I acknowledged him at the red light)


The (almost)-annual pilgrimage to Tacos Delta. Saw Paranorm. ChatGPT told us (and Wikipedia eventually confirmed) that Tarzana was named after the creation of its resident Edgar Rice Burroughs. Steve walked 15 miles the day before the race (!).


drop bags

Gear for the race:

  • I wore the most comfortable shoes I had, which were Hoka Clifton 9s, with probably 1500 miles on them (nearly falling apart, by the end they were definitely falling apart). I've been using the https://www.activeimprintsco.com Active Imprints insoles which are great for some mild form corrections.

  • At Edward's strong recommendation, I hiked with trekking poles. This turned out to be a huge help. Game changer. Kept me from tripping on my face countless times and the course has some steep climbs which you really can power up with. They were very common in use, and a few other runners I talked to regretted not bringing them (side note, what's the deal with the TSA requiring them to be in checked luggage? You're going to hijack a plane using trekking poles?! wtf).

  • Since the start was before dawn and the finish would almost certainly be after sunset, I needed a headlamp. I modded my Fenix HM50R to be waist-mounted (old SPIbelt, heh). And I had a cheapo 5 GBP LED headlamp as a backup. Seeing other people with waist-mounted lamps, though, makes me want one of those (much wider illumination area etc).

  • Backpack (Salomon Agile 6) with water bladder and stuff. I also carried my usual 24oz steel water bottle, which I usually keep and toss with my hands, which is enjoyable, but with trekking poles it was a pain in the ass, and while I could put it one of the front pockets of my backpack, it was a pain to take it in and out, especially as the day wore on. Noted.

  • I started trying tailwind a few months ago so I brought some packets of that, stroopwaffels, trader joe's peanut butter pretzels, and some almonds.

The race -- forecast was a low of 55 and a high of 72. Turns out the start was considerably colder, though, due to microclimates of the valley. But it was still quite pleasant having so recently been in the 20-degree highs of NY.


Psyched sideways

The first half of the race was more of a run than a race, as these things go.


The race begins on a road. Hey wait.

The water crossing at mile 2 was quite a bit higher and unavoidable this year. In 2020 I managed to keep my feet dry. The wool socks I was wearing quickly dried out and didn't give me any problems.









I changed my shirt and hat and dropped off my headlamp at the drop bag at mile 13, around that time I noticed some bits of chafing in spots, put some bodyglide on there and it stopped being a problem.

Peanut butter pretzels were good, stroopwaffels too. I think I might have accidentally dropped a wrapper though, ugh, sorry, hopefully someone picked it up. I put it in my pocket and closed the zipper but when I went to open the pocket at the aid station to dump the trash it was gone. Or maybe I misplaced it. Your brain sometimes loses track of all of these things.


why didn't someone tell me that water bottle looks ridiculous in the pocket?


group of mountain bikers having lunch, I assume. nice spot for it.


this time, on the descent to Bonsall, I could see the trail across the valley that we would later be on. makes me giddy!


settling in to the race and getting ready to fall apart at mile 22, Bonsall


At mile 22 I stopped, saw a guy (hi, Peter) whom I had previously mistaken for Steve, put some squirrel nut butter and a bandaid on a hotspot on my big toe (worked well, never used that stuff before). Filled up to the brim with water.



(crows getting a free ride on the ridge)

I paid more attention to birds this year, and not just the crows. I'd like to go back to these trails with a camera and big lens and time to spare.

The massive climb out of Bonsall was nice since I knew what to expect (in 2020 it was demoralizing, lol), but it was really hot. There was a stream crossing where dipping your hat in the water was an amazing feeling (though within minutes it was back to heat). If I had more time I would've sat in it.

The second half of the race was more difficult. I no longer had the energy to take pictures. The aid station around the halfway point had a lot of bacon. I really wanted some but I couldn't bring myself to eat any. This seems to happen to me at this point, nausea and stuff. I need to figure this out (brain thinks I have food poisoning or something?). Maybe I should've tried a gel. Doesn't require chewing and pure sugar, might have been worth the try. Hindsight.

At mile 37-ish, drop bag again, grabbed lights, long sleeved shirt, other hat. Didn't want to mess with my socks so kept my original pair.

I kept moving, snacking a little bit here and there, trying to down some tailwind along with the water, hanging on. By mile 43 (nearly 11 hours after the 5:30am start) I was 5 minutes ahead of my 2020 time, and only 10 minutes behind Steve, but I really couldn't eat anything. I overhead a couple of people drop to the 50 miler. My legs felt OK, and it turned out if I continued on with the 100k route, I could always drop at 50 miles (since it was a 6-mile each way out-and-back that turned around near the finish). So I continued on. Up a hill, then down a really massive hill. Going up the hill was fine. Going down the hill was difficult. I haven't done enough quad strength training. Tsk tsk. I ran a little bit of it but it was mostly walking. Ate maybe 3 almonds, drank a few swigs of tailwind. It was starting to get dark. At the bottom of the hill it was along a riverbed for a while. Lots of frog sounds. I saw Steve when I was about 15 minutes away from the 50 mile aid station (so his lead was up to about 30-45 minutes at that point, I guess?).

The aid station people gave me a quarter of a banana, which I ate. It was not easy. They were nice (they are all). Someone I talked to earlier in the race asked if I had a pacer for this part, then looked at me like I was crazy for not. I remembered this, and asked if there were any freelance pacers available. No such luck.

Did the riverbed commute back to the climb, now with my head(waist)lamp on. Coming down the hill was a race marshall, sweeping the course. Nobody else would be coming down the hill. I could see headlamps far ahead, and occasionally see them far behind me, but for a long time I saw nobody, and heard only the sounds of frogs and wind. The moon rose, it had a lot of clouds in front of it and looked very red on the horizon.

I running a huge calorie deficit and was having to regulate my climbing of the hill in order to prevent bonking. I'd go too hard and have to back off because I could feel it wouldn't be sustainable. This was the toughest part of the experience, I think, this climb. When I was eventually caught by another runner, it was nice.

Going over the hill and back down to the mile 43 aid station (again, though now at 55-ish), with 7 miles to go. This aid station is a bit remote and you can't drop out of the race there, and I guess it was getting late, so the aid station captain was really big on getting me moving. Tried to get me to eat, but when I did my best picky eater impression he said (very nicely -- everybody volunteering at the aid stations were amazing) something to the effect of "well water is what you need most right now, now get moving." So I did. I ended up not having any real calories to speak of for the last 20 miles of the race, heh. Though almost all of those 20 miles were walked, not run.

After that final aid station, the last 7 miles were challenging but also pretty straightforward, the finish was within reach, and I had plenty of time to not hit the cutoff at a walking pace. My underwear had bunched up and I had some pretty significant butt chafing but it was too late to do anything about it, just had to suffer with it. Should've checked in for it hours ago, doh. Once I got to the flat ground of the last mile, walking at about 13 minutes/mile to the finish felt pretty good (flat!). I was sort of hoping to be DFL, but not enough to slow down when I saw some headlamps behind me.


After more than 16 hours of running and hiking, Steve was waiting for me at the finish (having waiting 90 minutes! <3). There was food, but it would be hours until I could eat anything meaningful. We headed back to Tarzana, and watched some TV (was it Boys or 30 Rock? I can't remember) before crashing.

I got the shivers again. Seemed to be associated with movement, too. Didn't last too long, and not so bad. Way better than covid. Apparently it's about inflammation.


The next day Edward made us steak. Amazing.


There was ice cream, and a cold swim in a 55F pool. Total win.

Am I ready to do this race (including its 13,000ft of climbing and descent) again? No. But it won't be long.

4 Comments


January 4, 2024
2023 Retrospective

I could talk about things that were important in the world last year but I don't think I have anything terribly constructive to add, so instead I will post this:

At the end of 2021 I calculated some stats, but apparently I forgot to do anything for 2022. Here's 2023:

  • Code: git commits from 2022's 6.73+dev1231 to 2023's 7.07+dev1229 for which I am the claimed author (excluding merges): 2,158 (down from 2,264 in 2021)
  • Code: cumulative changes in repository (not just me, everything including Schwa and anything third-party): 1888 files changed, 108639 insertions(+), 80371 deletions(-) (also slightly less significant than 2021)

  • Foot-based-transport (from Strava): here, with my acquisition of a herniated disc in May, I started walking a lot and paying attention to the total foot-based miles and not just running: 2,519 miles in 712 hours and 58 minutes, with 154,329 feet of climbing (and similar descent, I imagine). Running was 572 miles of it (100 hours or so). I enjoyed the walking. I walked a number of NYRR races in order to 9+1 qualify for the NY Marathon next year, and walked the NY Marathon in about 5:19. It's not quite the same experience as running it, but still really enjoyable and a challenge.

  • Bicycling: I only strava'd 892 miles on a bike (since I ended up walking everywhere I could), though I missed some miles as I would often do Citibike shuffling on my walks, and wouldn't bother putting those in Strava (instead counting the walking portion of the shuffle). Still love my Casseroll Single. Got new wheels for it (the rims had suffered through enough braking with winter grit), and a front rack.
  • Bicycling: I rejoined Citibike in order to earn Bike Angels points, I think it ended up being a couple thousand but they don't really make it easy to see it over time. My lifetime total is now 3,125. I suspect I started this year with closer to 1,200.

  • Music played with others: 56 sessions (down from 62 in 2021), producing about 83 hours of music.
  • Music recorded: 21 doodles. also 16 super8 sessions (which produce about 9 hours of youtube content). Both quite a bit lower than 2021. Hmph.
I guess the overall trend is that I'm slowing down! Something to think about...

Recordings:

sandwich terrier

Comment...


October 7, 2023
C++ RAII optimization

Wanted to check my assumptions on C++ and the ability of modern compilers to optimize RAII (side note: I can never remember that abbreviation, always have to google it), so this morning I had a few moments of fun with godbolt:

    extern int gv, bar();
    
    template<class T> class saver {
      public:
      T save, *ptr;
      saver(T *p) : ptr(p) { save = *p; }
      ~saver() { *ptr = save; }
    };
    
    void foo_c() {
      int save = gv;
      gv = 1;
      bar();
      gv = save;
    }
    
    void foo_cxx() {
      saver<int> s(&gv);
      gv = 1;
      bar();
    }
    
    
When compiled with -O2 -fomit-frame-pointer -fno-exceptions, would foo_c() and foo_cxx() differ meaningfully? Output (x86-64 gcc 4.7.4, newer gcc versions are all similar):
    foo_c():
            push    rbx
            mov     ebx, DWORD PTR gv[rip]
            mov     DWORD PTR gv[rip], 1
            call    bar()
            mov     DWORD PTR gv[rip], ebx
            pop     rbx
            ret
    foo_cxx():
            push    rbx
            mov     ebx, DWORD PTR gv[rip]
            mov     DWORD PTR gv[rip], 1
            call    bar()
            mov     DWORD PTR gv[rip], ebx
            pop     rbx
            ret
    

So yeah, the optimizer does perfectly.

Recordings:

Yes, Exactly, Yes! - 1 -- [8:53]
Yes, Exactly, Yes! - 2 - Private Life -- [7:20]
Yes, Exactly, Yes! - 3 - Watch Your Step -- [2:46]
Yes, Exactly, Yes! - 4 - Watch Your Step (II) -- [2:05]
Yes, Exactly, Yes! - 5 - Self Imposed -- [4:39]
Yes, Exactly, Yes! - 6 - Dogs Will Rule the World -- [3:04]
Yes, Exactly, Yes! - 7 - Virgins Again -- [2:53]
Yes, Exactly, Yes! - 8 - Virgins Again (Again) -- [3:14]
Yes, Exactly, Yes! - 9 - The River -- [4:31]
Yes, Exactly, Yes! - 10 - Cosmic Background -- [3:32]
Yes, Exactly, Yes! - 11 -- [5:20]
Yes, Exactly, Yes! - 12 - Hindenburg -- [6:42]
Yes, Exactly, Yes! - 13 - Chosen by the Few -- [3:48]
Yes, Exactly, Yes! - 14 - Las Vegas -- [4:04]
Yes, Exactly, Yes! - 15 - No Big Benefactor -- [4:06]
Yes, Exactly, Yes! - 16 - Now We Understand -- [4:14]
Yes, Exactly, Yes! - 17 - Cast Iron Candy Bandit -- [3:10]
Yes, Exactly, Yes! - 18 - Dogs Will Rule the World (reprise) -- [3:37]
Yes, Exactly, Yes! - 19 - Find Me -- [5:01]
Yes, Exactly, Yes! - 20 - Old as Coal -- [4:33]
Yes, Exactly, Yes! - 21 -- [11:36]
Yes, Exactly, Yes! - 22 - Charlie (feat Cory Choy) -- [4:35]

Comment...


September 14, 2023
inefficient programming

Someone asked if I would post something about programming. I wish I had something interesting to offer. The best I can do is describe an area in our current work where there's a considerable productivity drain ("technical debt", I suppose).

We're still using Windows .rc files for dialog boxes. VC6 is my preferred dialog editor, but it has a limit of something like 32k or 64k controls in total for the entire .rc file, if you exceed that it crashes. We've long exceeded that, so now we pretty much edit .rc files by hand with lots of trial and error (I don't seem to be getting any better of adding/subtracting fixed values to the Nth column of a bunch of lines). We could temporarily trim the file, do the edits, then restore the rest, but meh. Or we could write a .rc file editor lol. At any rate it's completely inefficient.

On a more specific points related to that, adding options to REAPER's preferences takes far too much work. There's the manual .rc file editing, the juggling around of options in a fixed amount of space, moving things to other tabs, etc. It's stupid and a time suck. But there's no reasonable alternative without a ton of extra work. Some day, maybe.

So anyway, it's often the case where we want to add something simple, and a good half of the work is spent with UI nonsense. Yes yes we could move all of our preferences to a list of attributes and make it all generated from data and that would be great but that would be a huge project.

bonus:

People ask about making a mobile sequencer. The underlying core of a DAW would be the same, but doing the UI would require basically a separate implementation to be useable. I don't really want to maintain two DAWs. Also phones bleh (x 1000 -- the ecosystem, the lockeddownness, the lack of keyboard, the mercy of the OS, etc). :/

12 Comments


January 7, 2023
a (not) dangerous branch

Working on a fun REAPER branch relating to keyboard shortcuts. I will allow some pretty sweet things, but it will also give people a lot of rope to hang themselves with. You can have a bunch of alternate main keyboard mapping sections (which also affect mousewheel mappings), so you can switch sections by action/toolbar/menu/whatever.

You can also engage a section momentarily by action, so you could: make Ctrl+F be "momentarily use the main section named "FX", then that section could just have a ton of mappings to particular FX: Ctrl+F followed by E for ReaEQ, Ctrl+F followed by C for ReaComp, etc.

What's also fun is that when they are momentarily engaged, they act globally... so if you are in a text field and do Ctrl+F, then the following E or C still work, or if you have the Ctrl+F as a global hotkey, then that momentary switch makes the E or C effectively global too, but only when following the Ctrl+F.

But -- if you accidentally run an action perma-switching to a section that has no keyboard mappings... well nothing will work until you switch back via the correct action in the actions window, or you restart reaper. Which is where the rope to hang yourself is.

4 Comments


December 21, 2022
EEL2 Inception

(I posted this to Mastodon but really why not put it here too?)

In one of our REAPER development branches (and thus the latest +dev builds), there's now support for generating EEL2 code on the fly (for EEL reascripts, JSFX, video processors), using EEL2. I find this immensely pleasing.

To use this functionality, you can create an embedded script, using <? script code ?>, and that script has a separate variable/memory space, and can generate code using printf().

EEL2 often requires a lot of repetitive code to produce fast DSP code.

So for example, our loudness meter has a sinc filter that gets coefficients generated. Here's a before and after:

 function sinc_gen_slice(cs, o*) instance(sinc_gen_val slice_pos) global() (
   slice_pos = cs;
-  o.v00 = sinc_gen_val(); o.v01 = sinc_gen_val(); o.v02 = sinc_gen_val(); o.v03 = sinc_gen_val();
-  o.v04 = sinc_gen_val(); o.v05 = sinc_gen_val(); o.v06 = sinc_gen_val(); o.v07 = sinc_gen_val();
-  o.v08 = sinc_gen_val(); o.v09 = sinc_gen_val(); o.v10 = sinc_gen_val(); o.v11 = sinc_gen_val();
-  o.v12 = sinc_gen_val(); o.v13 = sinc_gen_val(); o.v14 = sinc_gen_val(); o.v15 = sinc_gen_val();
+  <? loop(x=0;sinc_sz, printf("o.v%02d = sinc_gen_val();%s",x,(x&3)==3?"\n": " "); x += 1) ?>
 );

There's some extra logic in there to produce identical output (including newlines) which isn't necessary, but added so I could test the output to make sure it didn't differ. The nice thing is, not only is this more readable and smaller, if you want to increase the filter size, you can without a ton of tedious and error-prone copy/paste.

Update, other tricks. If you want to make this code optional, you can do:

/* <? printf("%s/","*"); 
  printf("code which will only be executed on new jsfx/etc");
  printf("/%s","*");
?> */
and if you want either/or (new code vs legacy), you can do:
/* <? printf("%s/","*");
  _suppress=1; 
  printf("code which will only be executed on new jsfx");
  printf("/%s","*");
?> */
legacy code which will only be executed on old jsfx
/* <? _suppress=0; ?> */
(Forgot to mention earlier, you can set _suppress to have the preprocessor not output regular text)

2 Comments


December 4, 2022
Ray Miller 50 Miler Recap

(retroposted on December 17, 2022)

I took a ton of pictures on this race but I really have no use for them, nobody wants to come over and see my vacation slides, and I don't have a slide projector and also I took them on my phone which means they only exist as bits. I'm always looking for excuses to write about things, but it tends to be too much complaining about programming nonsense. So here are my photos, with explanations:




I flew into LAX on the Thursday. Decided to walk from the terminal to the rental car place. It's about a mile and a half, which if you've packed light is infinitely preferable to walk, especially in 55 degree weather, than to pile onto a rental car bus. Especially these days. I rented a car (brand new Kia sedan ftw), wandered my way around, got some lunch using a gift card I purchased in early 2020, mmm french toast, went for an easy run in Griffith Park to waste some time, it was really tough to not go more than a few miles. Checked into the guest house airbnb, went to bed at 7pm or so.




Friday involved going to Tacos Delta for chilaquiles. I'll leave this here. Kept to myself, worked a bit, went to bed around 7pm again.




Got up at 2:30am, left the airbnb at a little before 4am. Drove the long way to Malibu. Got to see places I occasionally went as a kid. Met Steve and Edward (and their friend Alex) at the start around 5:15am. There are other pictures with less fantastic lighting but really why when you have this one?




Something like 80 people, I guess? We start at 6am.

I should point out that the organizers mention that the course is well marked, but there is one turn that it's very important that the 50-mile runners make (there's also a 50k starting an hour later), and if you don't make the turn you'll end up running a bit over 50k. Why did I mention this?

The first few miles are a singletrack climb, which means the start position is very important. We held back, letting the faster people go ahead. Maybe we let too many. A little running, but a lot of fast hiking. Which was good, the last thing I wanted to do is go out too fast. I never know how these things will go, I mean usually it's fine but things will hurt and there will be suffering so better try to minimize it. And I'm on a low-mileage year. Anyway.




It starts getting light on the climb, 6:19am. Steve wants to go faster, runs a little bit of the climb, I somewhat keep up (catching up on the level bits or when he stops to take pictures).




It levels out a bit, there's some running, 6:40am. The aid station will come in another 20 minutes or so.




After the aid station (which was about 5 miles), some oranges, watermelon, water fillup, maybe some other snacks I forget now, we start a 6 mile loop with a little mud. Steve's in front of me here, at about 7:20am.




Ah the views, 7:28am.




The view ahead from the last shot, I love those shots of the trail ahead (or behind -- and more accurately the experience of seeing them in real life -- at home there's nothing more satisfying than seeing the Brooklyn Bridge ahead of you a mile away, and 1 WTC in the distance behind it, then finding yourself there by your feet). I'll try to point the trail shots out, if we can see with these low quality images I uploaded.




This one I could've left out, but hey 5 minutes passed and I can still see the ocean.









We head inland and it gets really muddy, I'm told this is due to rain. Tons of mud stick to your shoes, you end up tweaking your gait in order to try to shake it off as you go. Activating strange muscles. It gets a bit warm. Only a little bit. 7:49am. Another 10-15 minutes and you're back at the same aid station as before.




I left the aid station before Steve. As a result I was in front of him. There was a climb. I was not faster.




Oxnard, in the background, I assume! Our friend Fritz was always obsessed with that name. I meant to text him about that but didn't have much cell service. 8:26am.




After that climb, there was a pretty amazing descent, which I had a lot of fun on. Steve seemed to be on a phone call while he was running so I thought I'd give him his space. Near the bottom of the descent was the Valley of the Spiders[tm][cc](Andy). The spiders were considerate in marking their territory and I didn't feel threatened. 8:50am.




Just down the road a 100' from the spider web, it got really cold, this valley trapped that cold air, and the with the humidity there were these clouds forming. It was cool but didn't photograph well, just looks like dust here.




A short 10 minutes later, you pay the price of that descent, with a pretty steep fire road climb. I walked this (I walked all of the climbing really). As I was hiking up this, the leader for the 50k race ran past me. RAN. That did not look easy to do for a 10k let alone a 50k. At the top of that hill was the same aid station again (16 miles, 9:05am or so). Where I filled my water, ate some more, and left as soon as possible. Then about 100' down the road I stopped to clean out the mud from my sock which was messing with my big toe. Oh such stupid timing...




After that there was some nice downhill, then I ended up in a valley which was very warm and humid. This was probably as hot as I was all day, and it was at 9:30am.




On the climb out of the riverbed valley, it got cooler, but my hip was doing something funny, popping with each step that I walked (didn't have the issue running). I stopped to stretch a little, which didn't help, then found that I could adjust my gait slightly in order to avoid the popping. The popping didn't hurt but it also didn't seem like a good thing. The climb was nice, here's the view after crossing a gravel path that people were bicycling on (you can see them barely). It looked like a really nice place to ride. I do get jealous of California this time of year. 10:00am or so, 20 miles in.




I had a 10 minute stop at a NEW aid station, at 10:35-10:45 or so. At this point in addition to the eating and getting water (and watered down coke), I took my socks off, put some ointment and bandaids on my toes, which had been giving me problems (somewhat due to my mismanagement of them 4 weeks before at the NY marathon, another story which will not get documented). I also snugged my shoes slightly to try to keep some of the pressure off my toes (this ended up being an oops that I'm still paying for). Anyway 10-15 minutes after that aid station is this picture, mountains pretty. I like them. I start to climb them.




I go up what I thought was a really big hill (Strava tells me it was about 750'. OK not that big). At the top is this left turn. The one they mentioned at the start. It's a little tempting to just miss the turn and do a 50k. 11:15am, about 26 miles. I take the turn.

Side note: the course was very well marked, especially compared to the races in NJ I've done, but this is sort of the exception. They really should have a sign that says "50 mile runners: if you're not at mile 40 or so, turn around and make the turn!" Maybe missing turns and getting lost is a rite of passage for trail runners...




The climb continues! You can see the trail below... wait, shit, you can't. OK how about I "ENHANCE":




That's a person, I'm 79.3% sure. It could be Steve! I could easily check that in the days of Strava and GPS data but it's better not to know.




More climbing. 45 minutes and 2.5 miles later, nearing the top. This will be fun to go back down (we go out 7 miles or so and back another 7 miles to an aid station).




After that climb, there's still hills, some up, some down. I liked it better when the aid stations were closer together. You occasionally pass groups of tourists, which always feels odd, such differences in current experiences.




Still headed to the aid station, there's a view to the Northeast of some lake. I ponder whether it is artificial. 12:40pm, 31 miles, about to descend to the aid station.





Crow (or as I'm told, Raven), seen from the descent to the aid station.

Soon after, I arrive at the 33-ish mile aid station, and put on the best thing ever -- fresh socks. Long overdue. I try to eat some but it's getting more difficult. Sitting is nice. I arrive at around 12:50pm, leave around 1:05pm.

Out and back not so interesting, same thing in reverse. I see Edward before the big descent. Take a video of him running the other way. Share some ginger candy. He says Steve should be not too far behind him. We go our separate ways.





Take this video of running at the start of the big descent -- "Coming down the mountain" (around mile 38, 2:05pm)

I didn't mention it until now, but this whole race I've had songs from The Verve's "A Storm in Heaven" in my head. Butterfly, "The Sun, The Sun", Star Sail. I wondered if "The Sun, The Sea" is a reference to l'etranger. I'm not listening to anything but damn those songs just burn a hole in my ears. Maybe I get sick of them, or just my general starting-to-feel-awfulness projects to them (I still love that album and have happily listened to it since!).

I don't see Steve on the descent. I start to guess he missed the turn. D'oh.

The section of the climb that took 50 minutes to go up takes about 30 minutes to go down. Fun. My weak left calf starts feeling not great with every left step. Still fun though.




After that descent, some new territory. 2:30pm, around 39 miles. Eating ginger candies. So far between aid stations.




Nice trails though.




Ah another canyon, 3:15pm.




I think this was soon after the last one. The photographer was like "you're almost to the last aid station!" But those 3 or so miles took FOREVER. Boring flat jeep trail.

Get to the aid station, eat some stale Chipotle chips (they had water and gels and offered to make some soup but eh). Did some more toe management. This is the part of the race where I usually end up complaining and then after the fact regret the complaining. But anyway only like 4 miles to go, just one small climb and descent then it's done.




That climb went on way too long. The small climb is still 1000'. I talked to another person who was also complaining, though his excuse was that since September he had only run two 7 mile runs. pfft! and then he proceeded to go ahead and beat me by a solid 5-10 minutes. Ah, youth.




The climb kept going. More complaining.




Looking back.




My goal was to finish. Bonus to not finish in the dark. 4:30pm.




Damn, magic hour, 4:38pm. After taking this I enjoyed the descent, passed various hikers taking sunset pictures, we all agreed it was beautiful. Finished at something like 4:52pm. Took a few minutes before I could eat anything, had some quesadillas, chili, couldn't really stomach much. It was getting cold, so I took off. Saw in my text messages that Steve did in fact miss the turn (bummer).

Drove back to LA. Got back to the airbnb, ate some snacks, realized I didn't have enough of them, oops, took a shower, got chills, got in bed, felt really good under the covers. Whenever I'd get up to pee, massive shiver shiver chills.




7am Sunday, return to Tacos Delta. Glorious breakfast burrito made me whole. A few hours later, beer with salt and kebabs at Edward's. That was also amazing.

Thus concludes my story.

1 Comment


March 18, 2022
e-bikes

I recently got my first e-bike, and I have some thoughts:

(I've been riding in NYC for a number of years, most days, somewhere in the thousands of miles per year. Most of the time I ride a Salsa Casseroll Single with fenders, rack, panniers, 20 tooth cog for easier climbs, and most recently a Surly Open Bar handlebars and a stem riser for upright posture. Side note: a video of a recent ride. )

The last few (six?) months I've been dealing with a hamstring issue (too much running with poor biomechanics, curse you teenage self), and bicycling does seem to aggrevate it, so I decided to get an e-bike with a throttle in order to be able to rest a little while still living life and going places by bike. I got a RadRunner 2 (it seems pretty decent, reasonably priced, and you can set it up to carry passengers. I have some qualms from setting it up but I'll save those for another day).

This morning I rode from Tribeca to Union Square to pick up a few things from the green market, and back, usingthe throttle almost exclusively. I found myself going a lot faster than I normally ride, and worryingly defaulting into a "driving" mentality. It left a bad taste in my mouth.

Later in the day, I rode to my office/studio in Red Hook, via the Manhattan Bridge, and made a special effort to go at a usual (leisurely) pace. It worked, and I managed to stay in a better, more peaceful frame of mind, but it took mental effort. I will have to continue that effort.

I find I definitely prefer the peacefulness of riding regular (*cough* acoustic *cough*), but my hamstring appreciated the electric-ness. What's interesting, though, is the economics:

I recharged my battery after riding 15 miles (which would be about 90 minutes of riding at city speeds), and using a Kill-A-Watt, I measured 360Wh of power use at the mains power. I looked up electric rates, and a ballpark we're talking about $0.05 worth of electricity, and the battery probably had less than 0.05% (or $0.25) of its lifetime wear. If I had ridden my regular bike, I would've burned a few hundred calories at least, and unless I was extremely frugal in my eating (I am not), there's no way I would spend only $0.30 on replenishing those calories. So in some ways, this is more economical (and probably more efficient, too?). Obviously there are benefits to exercise but let's assume I have that taken care of anyway.

Delivery people all moved to e-bikes ages ago. There were stories in the news about how they needed them in order to keep up, but I never really realized that the economics of it, even if you are as fit as possible, made generally cheaper to use electricity than to eat the extra food!

It's very good that e-bikes have been made legal in NY, hopefully the parks will follow (it feels like there should be an ADA claim against the parks that ban them, as there are people who can ride e-bikes but can't ride acoustic bikes). I'm still stunned by the efficiency of this bike, even with its massive 3" wide tires and weighing in around 65lbs.

(Update March 19: I was curious how much electricity electric cars use by comparison… sounds like typical is 34kWh per 100 miles, or 340Wh per mile… assuming that holds up in the city, that’d make the electric bike use about 1/15th the power. which is roughly in line with the mass ratio...)

Recordings:

nothing that will be missed

Comment...


February 6, 2022
interview with Paul Davis

Paul Davis (fellow human being and author of the Ardour DAW) suggested on Twitter that we should have a conversation which would be recorded and available for download/stream via the internet on-demand (apparently this is a thing now?).

It seemed like a reasonable (or dare I say interesting, given our common experiences) suggestion, and generally my willingness to talk to people has a sort of vaguely gaussian curve where the X axis they want to talk to me and the Y axis is how willing I am to talk to them: if they don't want to talk to me at all, or if they REALLY want to talk to me, then I'm pretty much not interested, but if they're in the middle, then sure why not?

We had our interview (which was enjoyable, and it even would have been without a pasty on my desk staring me down for when it was over) using NINJAM in voice chat mode, which mostly works amazingly well, until it doesn't (and then you have to reinitialize the channels -- I've been meaning to fix that for years but meh). I haven't (nor will I likely) listened to it in its entirety, but hopefully I didn't make too much of a fool of myself (thank you Paul for editing it). Paul also is being very modest about his interviewing skills, I thought he did an excellent job (for an emacs user), but we're always our biggest critics (except those instances where you get asshole critics, but to be fair they are usually just assholes and not so much critics).

Anyway, here's the interview.

One final note, after our conversation I do find myself wondering how good of musicians we would both be by now, had we not chosen to write DAWs and instead had spent the last 36 collective years with our time devoted to playing rather than programming. It's a completely unknowable and unrealistic question, anyway: whether or not you consider programming an art, it shares with art the most difficult part which is maintaining an interest in a particular thing for extended periods of time. Would I be an amazing guitarist if I'd spent the last 15 years playing guitar for 8 hours a day? Probably. Could I possibly spend 15 years playing guitar for 8 hours a day? No chance in hell.

4 Comments


December 31, 2021
Year in Review

Here are my notes:

  • Code: git commits from 2020's REAPER v6.19+dev1231 to v6.43+dev1231 for which I am the claimed author (excluding merges): 2,264
  • Code: cumulative changes (I'm not sure how to limit this to just my commits so it's global, including third-party SDKs and schwa): 1711 files changed, 132415 insertions(+), 121934 deletions(-)

  • Running (from Strava): 1,366 miles, 44,850ft of climbing, 219 hours. Mileage about the same as 2019, though far less climbing (2019 was 66kft) and a half dozen fewer hours. I've had something or other bothering me nonstop all year but only rarely keeping me from running (at the moment my left glute/hamstring is a bit tight). My high water year for miles was 2017, which was 1,444 (with similar elevation of 44kft, covered in 216 hours). Ah youth.

  • Bicycling: 3,148 miles, 92,560ft of climbing, 346 hours (I'm sure I forgot to record some rides but then there's also probably some GPS errors giving me bonus miles).

    These were mostly as transportation or leisure rides, I only rode the road bike 67 of those miles (sorry, buddy. I'll take you out soon). The brompton got about 200 miles (mostly in San Francisco), and the cargo bike even got 100 miles.

    The Casseroll single speed is my favorite (thanks, Alex!). This year I replaced its handlebars (Surly Open Bar + stem extender, and a cupholder), seat, front tire, bottom bracket, freewheel (after the old one failed in February, though it was fixed gear 3:1 for a good 6 months before going back to 12:5 freewheel), and twice (March and December) its chain. The brompton also got a new chain.

  • Music played with others: 62 sessions, producing about 87 hours of (very-loosely) edited music. The pandemic made this difficult. Singing with a mask on has its own challenges.
  • Music recorded alone: I did about 20 super8 sessions, producing about 9.5 hours of music/youtube videos. Also I recorded 37 doodles, about 2 hours of music.

  • It is probably for the best that I don't have many consumption numbers, such as paper products, disposable masks worn, etc.


Comment...


March 22, 2021
Ah, Big Sur

This most recent (as of this blog post) macOS update (and new architecture) has raised a number of issues with REAPER development -- I'm documenting them here in hopes of it being useful to someone:

  • If you're using the Hardened Runtime (for notarization) and have the com.apple.security.device.audio-input entitlement set, if you link against the latest SDKs you also _MUST_ have the NSMicrophoneUsageDescription set in your application's .plist, otherwise it will never prompt.

  • If you create a CGImage using CGImageCreate(), draw it using CGContextDrawImage(), and release it, that underlying image data is accessed by the system at a later time when the drawing actually occurs. This will cause all kinds of bugs in all kinds of software. We work around it by forcing Metal on various views where this isn't safe.

  • If you call MIDISend() with 250 or more events at the same timestamp, it will crash. (thanks to @helgoboss for isolating this)

  • Rosetta2 is amazing -- just don't try to get it to run x87 code. EEL2 still generates x87 code, so JSFX on REAPER-intel on an M1 is incredibly slow. A quick benchmark in EEL2 gave me this: arm64 native: 1.25s, arm64 bytecode: 4.18s, rosetta2 x86_64 bytecode 9.18s, rosetta2 x86_64 x87 code 59s. (bytecode is EEL2 in portable non-JIT mode). The benchmark I used was actually pretty low on math, I think on DSP code it's probably even worse, like a 100x slowdown.

    side note: so now, I'm trying to figure out the best way to deal with this. I did an EEL2-SSE branch a while back, and I have it working again, but it's about 20% slower than the x87 version in a lot of important cases. Tempted to make a jsfx-sse.dylib and only use it if running in Rosetta2. Also tempted to overhaul EEL2 to optimize for non-stack based architectures (which would also greatly improve the aarch64 version). The answer probably is something more incremental, like introduce some helpful optimizations into EEL2's code generation that will help get the SSE version up to parity. Of course, there will be little quirks that differ between the SSE and x87 versions, so those will need ages and ages of testing to get ironed out.


There were other things that came up that aren't as interesting. When launching Audio MIDI Setup.app, the new path is /System/Applications/Utilities/Audio MIDI Setup.app rather than /Applications, for example. Apple likes to change the appearance of NSTableViews and then provide ways to get them partially back to their previous style, but not all the way. Stuff like that... Dealing with macOS updates and compatibility is really not enjoyable. So tiring. Though the x87 vs SSE thing isn't their fault -- no x86_64 system has ever not had SSE...

4 Comments


July 22, 2020
happy birthday, autobuild.php

I randomly was doing some historical analysis preparing for the next REAPER release (tomorrow), and I noticed that on this day 10 years ago, the REAPER buildfarm first ran. Here's the test commit:

commit 306defecae4c7607b89b318f7caf72dc9ac99e1f (tag: v3.66pre4testb)
Author: justin <justin@4fc7d1b0-fb43-634d-aa29-800e4c0b6062>
Date:   Thu Jul 22 19:36:48 2010 +0000
    WANT_BUILD: 3.66pre4testb
Happy Birthday, autobuild.php!

Here is my analysis (it's noisy, at times, due to CR/LF conversions, updating various libraries, etc):
v3.67    Aug 29 2010 : 567 files changed, 54099 insertions(+), 2957 deletions(-)
v3.671   Aug 29 2010 : 5 files changed, 14 insertions(+), 21 deletions(-)
v3.672   Aug 30 2010 : 8 files changed, 41 insertions(+), 13 deletions(-)
v3.68    Sep 11 2010 : 37 files changed, 709 insertions(+), 337 deletions(-)
v3.69    Sep 20 2010 : 18 files changed, 265 insertions(+), 142 deletions(-)
v3.7     Sep 27 2010 : 17 files changed, 270 insertions(+), 117 deletions(-)
v3.71    Sep 28 2010 : 6 files changed, 35 insertions(+), 14 deletions(-)
v3.72    Oct 19 2010 : 42 files changed, 1911 insertions(+), 224 deletions(-)
v3.73    Nov 17 2010 : 43 files changed, 4197 insertions(+), 180 deletions(-)
v3.74    Dec 24 2010 : 21 files changed, 277 insertions(+), 123 deletions(-)
v3.75    Jan 26 2011 : 26 files changed, 193 insertions(+), 69 deletions(-)
v3.76    Apr 25 2011 : 97 files changed, 3491 insertions(+), 1020 deletions(-)
v3.77    Jul 22 2011 : 24 files changed, 543 insertions(+), 251 deletions(-)
v3.78     Aug 2 2011 : 29 files changed, 366 insertions(+), 107 deletions(-)
v4.0      Aug 3 2011 : 2451 files changed, 138908 insertions(+), 39475 deletions(-)
v4.01     Aug 4 2011 : 18 files changed, 173 insertions(+), 39 deletions(-)
v4.02    Aug 22 2011 : 78 files changed, 4755 insertions(+), 880 deletions(-)
v4.10    Sep 30 2011 : 155 files changed, 20949 insertions(+), 3441 deletions(-)
v4.11    Nov 12 2011 : 186 files changed, 32967 insertions(+), 23010 deletions(-)
v4.111   Nov 13 2011 : 8 files changed, 13 insertions(+), 11 deletions(-)
v4.12    Nov 19 2011 : 18 files changed, 1521 insertions(+), 175 deletions(-)
v4.13    Nov 21 2011 : 8 files changed, 52 insertions(+), 24 deletions(-)
v4.14    Dec 18 2011 : 133 files changed, 5835 insertions(+), 4069 deletions(-)
v4.15    Jan 15 2012 : 196 files changed, 37371 insertions(+), 4690 deletions(-)
v4.20    Mar 20 2012 : 388 files changed, 47263 insertions(+), 20544 deletions(-)
v4.21    Mar 24 2012 : 57 files changed, 12296 insertions(+), 392 deletions(-)
v4.22     Apr 5 2012 : 69 files changed, 390 insertions(+), 1381 deletions(-)
v4.25    Jul 12 2012 : 201 files changed, 21357 insertions(+), 6453 deletions(-)
v4.26    Aug 17 2012 : 246 files changed, 18401 insertions(+), 1558 deletions(-)
v4.30    Nov 13 2012 : 183 files changed, 10010 insertions(+), 2961 deletions(-)
v4.31    Nov 23 2012 : 52 files changed, 869 insertions(+), 357 deletions(-)
v4.32    Jan 15 2013 : 128 files changed, 14765 insertions(+), 2422 deletions(-)
v4.33    Apr 17 2013 : 219 files changed, 16665 insertions(+), 1787 deletions(-)
v4.40    Apr 25 2013 : 102 files changed, 6259 insertions(+), 895 deletions(-)
v4.401   Apr 27 2013 : 18 files changed, 59 insertions(+), 31 deletions(-)
v4.402   Apr 27 2013 : 8 files changed, 36 insertions(+), 14 deletions(-)
v4.5     Aug 29 2013 : 368 files changed, 25469 insertions(+), 27670 deletions(-)
v4.51    Aug 30 2013 : 10 files changed, 212 insertions(+), 61 deletions(-)
v4.52     Sep 5 2013 : 21 files changed, 663 insertions(+), 299 deletions(-)
v4.53     Oct 4 2013 : 93 files changed, 3772 insertions(+), 4109 deletions(-)
v4.54     Oct 7 2013 : 4 files changed, 47 insertions(+), 36 deletions(-)
v4.55    Oct 27 2013 : 95 files changed, 8253 insertions(+), 1605 deletions(-)
v4.56     Nov 8 2013 : 152 files changed, 3625 insertions(+), 1870 deletions(-)
v4.57    Nov 16 2013 : 107 files changed, 3765 insertions(+), 901 deletions(-)
v4.58    Dec 16 2013 : 116 files changed, 12598 insertions(+), 2454 deletions(-)
v4.581   Dec 17 2013 : 21 files changed, 433 insertions(+), 102 deletions(-)
v4.59    Jan 13 2014 : 142 files changed, 13507 insertions(+), 7446 deletions(-)
v4.591   Jan 17 2014 : 8 files changed, 251 insertions(+), 246 deletions(-)
v4.60    Feb 28 2014 : 638 files changed, 230240 insertions(+), 17928 deletions(-)
v4.601    Mar 2 2014 : 5 files changed, 25 insertions(+), 9 deletions(-)
v4.602    Mar 2 2014 : 4 files changed, 25 insertions(+), 24 deletions(-)
v4.61    Mar 20 2014 : 132 files changed, 4096 insertions(+), 2087 deletions(-)
v4.611   Apr 13 2014 : 64 files changed, 2871 insertions(+), 462 deletions(-)
v4.62    May 12 2014 : 215 files changed, 3858 insertions(+), 2270 deletions(-)
v4.7     Jul 10 2014 : 191 files changed, 8334 insertions(+), 3350 deletions(-)
v4.71    Jul 15 2014 : 35 files changed, 530 insertions(+), 321 deletions(-)
v4.72    Aug 14 2014 : 94 files changed, 3311 insertions(+), 1139 deletions(-)
v4.721   Aug 19 2014 : 12 files changed, 30 insertions(+), 18 deletions(-)
v4.73    Sep 17 2014 : 85 files changed, 4013 insertions(+), 276 deletions(-)
v4.731   Sep 26 2014 : 9 files changed, 1612 insertions(+), 20 deletions(-)
v4.75     Nov 7 2014 : 93 files changed, 1497 insertions(+), 2181 deletions(-)
v4.76    Dec 15 2014 : 1743 files changed, 2014 insertions(+), 19752 deletions(-)
v5.0     Aug 11 2015 : 4449 files changed, 291272 insertions(+), 39450 deletions(-)
v5.01    Aug 26 2015 : 123 files changed, 17743 insertions(+), 11269 deletions(-)
v5.011   Sep 10 2015 : 4 files changed, 17 insertions(+), 3 deletions(-)
v5.02    Sep 22 2015 : 139 files changed, 5708 insertions(+), 3344 deletions(-)
v5.03    Sep 24 2015 : 14 files changed, 169 insertions(+), 51 deletions(-)
v5.04     Oct 1 2015 : 27 files changed, 460 insertions(+), 129 deletions(-)
v5.1     Nov 14 2015 : 159 files changed, 10791 insertions(+), 3460 deletions(-)
v5.11    Dec 25 2015 : 195 files changed, 25500 insertions(+), 5874 deletions(-)
v5.111   Jan 12 2016 : 27 files changed, 242 insertions(+), 77 deletions(-)
v5.12    Jan 21 2016 : 179 files changed, 7582 insertions(+), 2736 deletions(-)
v5.15     Feb 9 2016 : 123 files changed, 4247 insertions(+), 2494 deletions(-)
v5.16     Mar 3 2016 : 96 files changed, 5232 insertions(+), 1208 deletions(-)
v5.17    Mar 24 2016 : 111 files changed, 17317 insertions(+), 1262 deletions(-)
v5.18     Apr 4 2016 : 43 files changed, 959 insertions(+), 192 deletions(-)
v5.20    May 17 2016 : 284 files changed, 29563 insertions(+), 4198 deletions(-)
v5.201   May 23 2016 : 8 files changed, 57 insertions(+), 18 deletions(-)
v5.21    Jun 15 2016 : 71 files changed, 2045 insertions(+), 1270 deletions(-)
v5.211   Jun 19 2016 : 11 files changed, 152 insertions(+), 69 deletions(-)
v5.22    Jul 14 2016 : 88 files changed, 3191 insertions(+), 850 deletions(-)
v5.23    Aug 13 2016 : 93 files changed, 7934 insertions(+), 3799 deletions(-)
v5.24     Sep 4 2016 : 75 files changed, 2246 insertions(+), 854 deletions(-)
v5.25    Sep 19 2016 : 264 files changed, 2827 insertions(+), 1372 deletions(-)
v5.26     Oct 5 2016 : 37 files changed, 855 insertions(+), 366 deletions(-)
v5.27    Oct 19 2016 : 41 files changed, 2850 insertions(+), 544 deletions(-)
v5.28     Nov 6 2016 : 84 files changed, 2655 insertions(+), 1392 deletions(-)
v5.29    Nov 25 2016 : 68 files changed, 4384 insertions(+), 3591 deletions(-)
v5.30    Dec 18 2016 : 231 files changed, 14626 insertions(+), 9300 deletions(-)
v5.31    Dec 24 2016 : 1021 files changed, 126 insertions(+), 285150 deletions(-)
v5.311   Dec 27 2016 : 10 files changed, 26 insertions(+), 18 deletions(-)
v5.32    Jan 15 2017 : 173 files changed, 32914 insertions(+), 13114 deletions(-)
v5.33     Feb 4 2017 : 48 files changed, 2551 insertions(+), 1198 deletions(-)
v5.34    Feb 22 2017 : 67 files changed, 1042 insertions(+), 642 deletions(-)
v5.35    Feb 28 2017 : 20 files changed, 121 insertions(+), 32 deletions(-)
v5.40    Mar 23 2017 : 112 files changed, 5515 insertions(+), 1297 deletions(-)
v5.50    Sep 13 2017 : 368 files changed, 33265 insertions(+), 11592 deletions(-)
v5.51    Sep 28 2017 : 90 files changed, 1593 insertions(+), 622 deletions(-)
v5.52     Oct 3 2017 : 11 files changed, 51 insertions(+), 32 deletions(-)
v5.60    Oct 23 2017 : 197 files changed, 28306 insertions(+), 3367 deletions(-)
v5.61    Oct 27 2017 : 21 files changed, 142 insertions(+), 78 deletions(-)
v5.62     Nov 7 2017 : 53 files changed, 1547 insertions(+), 923 deletions(-)
v5.7     Dec 12 2017 : 268 files changed, 52301 insertions(+), 2872 deletions(-)
v5.70    Dec 12 2017 : 14 files changed, 15 insertions(+), 26 deletions(-)
v5.75    Feb 16 2018 : 344 files changed, 5973 insertions(+), 5858 deletions(-)
v5.76    Feb 19 2018 : 20 files changed, 182 insertions(+), 113 deletions(-)
v5.77     Mar 8 2018 : 40 files changed, 1260 insertions(+), 308 deletions(-)
v5.78    Mar 24 2018 : 59 files changed, 3495 insertions(+), 2821 deletions(-)
v5.79    Apr 16 2018 : 144 files changed, 1869 insertions(+), 962 deletions(-)
v5.80    Apr 24 2018 : 32 files changed, 361 insertions(+), 104 deletions(-)
v5.90    May 23 2018 : 109 files changed, 4021 insertions(+), 1999 deletions(-)
v5.91     Jun 2 2018 : 46 files changed, 382 insertions(+), 138 deletions(-)
v5.92    Jun 20 2018 : 50 files changed, 2345 insertions(+), 1762 deletions(-)
v5.93    Jul 17 2018 : 92 files changed, 18145 insertions(+), 514 deletions(-)
v5.94     Aug 2 2018 : 130 files changed, 28495 insertions(+), 6527 deletions(-)
v5.941    Aug 4 2018 : 7 files changed, 33 insertions(+), 13 deletions(-)
v5.95    Sep 10 2018 : 139 files changed, 3593 insertions(+), 794 deletions(-)
v5.96     Oct 8 2018 : 73 files changed, 1864 insertions(+), 636 deletions(-)
v5.961   Oct 18 2018 : 29 files changed, 443 insertions(+), 189 deletions(-)
v5.962   Nov 16 2018 : 780 files changed, 199373 insertions(+), 40684 deletions(-)
v5.963   Nov 21 2018 : 6 files changed, 34 insertions(+), 15 deletions(-)
v5.964   Dec 17 2018 : 115 files changed, 3749 insertions(+), 1464 deletions(-)
v5.965   Dec 18 2018 : 15 files changed, 70 insertions(+), 27 deletions(-)
v5.97    Feb 21 2019 : 172 files changed, 24428 insertions(+), 3727 deletions(-)
v5.971   Feb 25 2019 : 13 files changed, 169 insertions(+), 81 deletions(-)
v5.972    Mar 6 2019 : 75 files changed, 1877 insertions(+), 579 deletions(-)
v5.973   Mar 11 2019 : 26 files changed, 284 insertions(+), 57 deletions(-)
v5.974    Apr 6 2019 : 83 files changed, 2747 insertions(+), 1552 deletions(-)
v5.975   Apr 29 2019 : 183 files changed, 6242 insertions(+), 3998 deletions(-)
v5.976    May 2 2019 : 21 files changed, 159 insertions(+), 118 deletions(-)
v5.977    May 6 2019 : 14 files changed, 152 insertions(+), 83 deletions(-)
v5.978   May 10 2019 : 29 files changed, 331 insertions(+), 312 deletions(-)
v5.979   Jun 17 2019 : 82 files changed, 2838 insertions(+), 1029 deletions(-)
v5.980   Jul 11 2019 : 59 files changed, 1348 insertions(+), 478 deletions(-)
v5.981   Jul 21 2019 : 32 files changed, 347 insertions(+), 128 deletions(-)
v5.982   Aug 17 2019 : 70 files changed, 1855 insertions(+), 609 deletions(-)
v5.983   Aug 29 2019 : 29 files changed, 178 insertions(+), 92 deletions(-)
v5.984   Oct 11 2019 : 39 files changed, 804 insertions(+), 247 deletions(-)
v5.985   Nov 13 2019 : 107 files changed, 1881 insertions(+), 1004 deletions(-)
v5.986   Nov 18 2019 : 41 files changed, 11893 insertions(+), 116 deletions(-)
v5.987   Nov 19 2019 : 15 files changed, 68 insertions(+), 19 deletions(-)
v6.0      Dec 3 2019 : 2872 files changed, 32398 insertions(+), 14335 deletions(-)
v6.01     Dec 6 2019 : 91 files changed, 547 insertions(+), 447 deletions(-)
v6.02    Dec 16 2019 : 595 files changed, 1865 insertions(+), 842 deletions(-)
v6.03    Jan 13 2020 : 52 files changed, 854 insertions(+), 585 deletions(-)
v6.04    Feb 20 2020 : 131 files changed, 5384 insertions(+), 1148 deletions(-)
v6.05     Mar 5 2020 : 58 files changed, 2451 insertions(+), 898 deletions(-)
v6.06    Mar 28 2020 : 501 files changed, 1308 insertions(+), 250389 deletions(-)
v6.07    Mar 29 2020 : 4 files changed, 11 insertions(+), 7 deletions(-)
v6.08     Apr 3 2020 : 63 files changed, 1585 insertions(+), 880 deletions(-)
v6.09    Apr 27 2020 : 135 files changed, 6386 insertions(+), 9265 deletions(-)
v6.10     May 9 2020 : 126 files changed, 5546 insertions(+), 2309 deletions(-)
v6.11    May 23 2020 : 795 files changed, 5893 insertions(+), 22413 deletions(-)
v6.12    Jun 14 2020 : 611 files changed, 7911 insertions(+), 120505 deletions(-)
v6.13    Jul 22 2020 : 297 files changed, 9595 insertions(+), 3189 deletions(-)


Comment...


March 15, 2020
Super8 (Social Distancing)

I bicycled from Manhattan to Brooklyn to play the piano some, and do a little Super8 session:
(youtube link)

On Wednesday, I had gone to the studio (which is right by Fairway) in the afternoon and stayed until the evening. I went into Fairway, which was pretty normal-ish. After my cancelled band practice and trip home, there had been a presidential address, which was a total failure in pretty much every way I could see, other than getting peoples attention. The next day, I went to the studio, and stopped in Fairway on my way home to get a few more things, and it was a total madhouse. Such a difference in a day.

Anyway since Wednesday we've been practicing Social Distancing, which is both easy and not easy. It's only been 5 days but it's going to be challenging.

A friend and I discussed food strategies via text. What Allison and I are doing now is basically trying to keep a stocked pantry with a list of things that we wouldn't mind having more of, and when we need something, we'll go buy that thing we need and other things from the list of things that we wouldn't mind having more of.

Last Sunday we were scheduled to fly to California, and yesterday I was scheduled to run a 50 miler in Marin County. We cancelled our trip the day before, which made me sad but after an exercise in sunk cost (figuring the difference in cost to proceed with the trip vs cancel, ignoring non-refundable stuff), it made total sense. Yesterday I found out the race was cancelled anyway.

There's my rambling. Someone on twitter said now was a good time to try journalling. My first thought is "my filesystems are all ext4, baby." I lied, I'm on a mac at this moment.

Recordings:

super8_distance - 1 -- [32:10]
super8_distance - 2 -- [5:56]
super8_distance - 3 -- [0:49]

Comment...


February 11, 2020
SOB 50

Oops I haven't updated here in months. I posted a thread to Twitter the other night, which I'm now going to post here since it's more appropriate here anyway (I was tired and lazy and on my phone). So here goes (with [edits]):

Yesterday [Saturday, 3 days ago] I did my first 50 mile ultra[marathon]. It was in California, near Malibu [Edit: The race is called the Sean O'Brien 50]. I woke up at 3:30am, left the house at 4:10, picked up @runviper [Edward] at 4:35, arrived at the start at about 5:15, before sunrise. It was cold, 40F [reminded me of home], and since the full supermoon was low on the horizon, dark.

You will see a lot of me making this face in this thread:

The start was supposed to be at 6:00 sharp, though I'm pretty sure it was 30 seconds late:

[That's the organizer with the megaphone, I believe. In the final race information email, there was a really thoughtful paragraph which stuck with me, I'll quote it here:

    I believe we are capable of anything we set our minds to. If you visualize it enough, and work hard you can make it happen. Remember that it's a "gift" that we get to run on the trails. There are people who can't even get out of bed. You "get" to participate in an ultra. Enjoy the experience. Be in the moment, and just have fun. It will all come together on race day if you stay positive, and remember what a blessing it is to do what we do. Not even 1% of the population will ever do what you are going to do in less than 1 week. Pretty awesome when you think of it like that? See ya soon my friends!!
Anyway...]

The first couple miles were crowded enough that I didn’t stop to take a picture. It went up a nice hill which made me feel powerful in my ability to climb it while running, then down the other side, through some more park, and then we arrived at a stream.

It was perhaps a small creek, but big enough that crossing it was tricky. There was a loose rope going across to help. A headlamp went flying and started floating down the water. I had a moment of heroism when I recovered it. I crossed with dry feet. Not bragging. After the creek crossing we started climbing again, and the sky started getting light.


and then the sun rose. Around this time I was able to feel my fingers again. I had thin cherry tree 10-miler branded gloves on but they could only do so much. This was almost an hour in, probably around 4 miles in, having climbed about 1500’

After we ascended another 10 minutes or so, the fog covering the Pacific came into view:




There was a photo-op moment going up over some rocks. Approaching it I figured that round thing would be a microwave dish or something but it was actually a light for a photographer.. I’ll see the results eventually I imagine. [edit: that photo wasn't great and too expensive to buy!]

[The] first aid station was about 7 miles in (hour and 40 minutes after the start). Mmm watermelon and oranges. Also potatoes and salt. Eating felt good. [Spent about 2.5 minutes here]

The next hour or so was mostly single track and had a good amount of variety. The charcoaled wood from the fires of last year offered a contrasting element to the blissful joy of the run.





At about 9am (3 hours elapsed, about 13mi, 3200’ ascent) after crossing above a tunnel, we arrived to the second aid station, which had expanded offerings from the first. Sandwiches! PB&J awesome! In hindsight I should’ve had some candy. Regretting not having candy. Getting warm.


There were drop bags at that aid station... dumped my wool shirt, headlamp, picked up sunblock. [spent about 7 minutes here] Soon enough it got very bright, and less photogenic. (note re: video — Spaceballs reference, had plenty of water):

After another hour or so (10:15am?) we crossed over a pass and could see the marine layer again. ~17 miles and 4300’ climbing cumulative...



10 minutes downhill and we arrived at an aid station. Lemonade, fruit, sandwiches, potatoes, consumed. @runviper made a taco, I questioned his judgment for eating beans, then proceeded to join him. No regrets [on the beans] (for me at least) [regrets on not eating candy]. [spent about 5 minutes here]

At this aid station they explained we were 19 miles in, we just had to do 3 miles down to the next aid station, then 8 more miles back up another trail, then the 19 miles back to the start. Legs felt pretty good... time to descend. Oof.


3 miles, 1500’ of descent, and maybe 30 minutes later, the cracks started to show. That tight IT band thing you feel sometimes? hello


eat eat eat [spent about 7 minutes] then back up the hill with full water, going back to where we were, in 8 miles instead of 3. Hey why is it so steep?



After having climbed 1800’ for an hour, you suddenly realize you’re on top of the wrong mountain [edit: but still on the course -- it is a torturous course], and the aid station is a tiny speck on the horizon. There is a gorge separating you from it.

The aforementioned IT/knee thing made the 800’ descent difficult, especially the steeper parts. So I was actually happy to be climbing again, which was good because there was 1000’ to go for the aid station


These 8 miles were brutal. The sun was strong, it was hot, and seeing the expanse between you and where you need to be was intimidating. And knowing once you get to the aid station, you still have 19 miles to go (which are largely downhill, ugh) After having gotten to the aid station, food [nutella (gnutella) sandwiches, mmm. apparently they had run out of water too, but had since gotten more], ice in the face, etc [spending about 8 minutes], we continue on. There’s a small descent, a few hundred feet later I decide I must stop and get a rock out of my shoe. We are 31 miles in, 7300’ of ascent, it’s 1:40pm, there have been rocks in my shoes all day. I probably also tried to stretch my IT. anyway we climb 600’ to go back over the pass, and look back at the ocean:


Now it’s just a short 6 miles to the bag-drop aid station. At some point around here I started using anti-chafe stuff everywhere i felt twinges. Seemed to work but could’ve been placebo. I was wincing on all of the steeper descent bits, not taking too many photos

Get to the mile 37 aid station, change shirts back to wool, grab headlamp. Eat a little but damn at this point I’m sick of food. [Should've started eating candy. changed socks, win. Drank cold brew coffee from drop bag. Both win. Also did some stretching of the IT. total time here was 13 minutes]



And another 6 miles of mid-afternoon. With 2000’ of ascent (not too gradual, plenty of my new favorite thing at this point: descent)




We get to the final aid stop at around 5pm (that 6 miles took a while!), just 7 miles to go! Stretch again here [spent about 8 minutes here -- total aid station time was about 50 minutes]


After this aid station it really got to be the magic hour:



and the fog and mist:

the full super moon returned, too




the anticlimactic ending is that I stopped taking pictures, we turned on headlamps, I endured the descents, and in the last 2 miles got my feet soaked trying to cross the stream that I had managed to cross dryly in the morning [tweaked an old injury in my arm doing this, though, hanging on to the rope crossing the stream. didn't really realize it at the time, but it became apparent by Monday], and despaired that the trail never seemed to end.

and then finally finished 50ish miles with approx 11,000ft of ascent and 11,000ft of descent, in a bit less than 13 hours. And @runviper [Edward] was kind enough to wait for me to catch up before crossing the finish.

update: Monday: legs feeling pretty good! had some nice walks yesterday and a hike today. much better than post-marathon, which makes sense since most of it was hiking...

update: Tuesday: flew home, had an easy run.



Comment...


October 20, 2019
Decanted Youth, live Open Studios video

We played again in the studio last weekend, here's the first of two shows:
(youtube link)
(the next show will be posted soonish)

Comment...


July 8, 2019
macOS screen updating, part III: 2019

Five years ago, in the year of our lord 2014, I wrote about the difficulties of drawing bitmapped graphics to screen in macOS, and I revisited that issue again in the winter of 2017.

Now, I bring you what is hopefully the final installment (posted here for usefulness to the internet-at-large).

To recap: drawing bitmapped graphics to screen was relatively fast in macOS 10.6 using the obvious APIs (CoreGraphics/Quartz/etc), and when drawing to non-retina, normal displays in newer macOS versions. Drawing bitmapped graphics to (the now dominating) Retina displays, however, got slow. In the case of a Retina Macbook Pro, it was a little slow. The 5k iMacs display updates are excruciatingly slow when using the classic APIs (due to high pixel count, and expensive conversion to 30-bit colors which these displays support).

The first thing I looked at was the wantsLayer attribute of NSView:

  • If you use "mynsview.wantsLayer = YES", things get better. On normal displays, slightly, on a Retina Macbook Pro's display, quite a bit better. On a 5k iMac's display, maybe slightly better. Not much.
  • Using the wantsLayer attribute seems to be supported on 10.6-current.
  • For views that use layers, you can no longer [NSView lockFocus] the view and draw into it out of a paint cycle (which makes sense), which prevents us from implementing GetDC()/ReleaseDC() emulation.

After seeing that enabling layers wasn't going to help the 5k iMacs (the ones that needed help the most!), I looked into Metal, which is supported on 10.11+ (provided you have sufficient GPU, which it turns out not all macs that 10.11 supports do). After a few hours of cutting and pasting example code in different combinations and making a huge mess, I did manage to get it to work. I made a very hackish build of the LICE test app, and had some people (who actually have 5k iMacs) test the performance, to see if would improve things.

It did (substantially), so it was followed by a longer process of polishing the mess of a turd into something usable, which is not interesting, though I should note:
  • If you want to update the entire view every time, you can configure a CAMetalLayer properly and just shove your bits into the CAMetalLayer's texture and tell it to present and avoid having to create another texture and a render pipeline and all of that nonsense.
  • If you want to do partial window updates (partial-invalidates, or a GetDC()-like draw), then you have to create a whole render pipeline, a texture, compile shaders, blah blah blah ugh.
  • There's a bunch more work that needs to get done to make it all work (and adapt to changing GPUs, blah blah blah)...
This stuff is now in the "metal" branch of swell in WDL, and will go to master when it makes sense. This is what is in the latest +dev REAPER builds, and it will end up in 6.0. I'm waiting for it to completely bite me in the ass (little things do keep coming up, hopefully they will be minor).

As one final note, I'd just like to admonish Apple for not doing a reasonable implementation of all of this inside CoreGraphics. The fact that you can't update the 5k iMac's screen via traditional APIs at an even-halfway-decent rate is really stupid.

P.S. It does seem if you want to have your application support Dark Mode, you can't use [NSView lockFocus] anymore either, so if you wish to draw-out-of-context, you'll have to use Metal...

Recordings:

Decanted Youth - 1 - Supposed to Be -- [8:14]
Decanted Youth - 2 - (Vaguely Instrumental) Legacy -- [16:11]
Decanted Youth - 3 - (Vaguely) Round and Round -- [5:15]
Decanted Youth - 4 - The Squeeze -- [6:31]
Decanted Youth - 5 -- [3:16]
Decanted Youth - 6 - (mini cover medley) -- [10:03]
Decanted Youth - 7 -- [9:15]
Decanted Youth - 8 -- [8:26]
Decanted Youth - 9 - Trees and Mold -- [9:37]
Decanted Youth - 10 -- [4:53]
Decanted Youth - 11 -- [9:05]
Decanted Youth - 12 -- [7:02]

6 Comments


May 21, 2019
Copenhagen Marathon

This was the second marathon road course I've run (after NY) -- while the course was nearly flat, it was challenging because of:

  • Lots of people going through many narrow sections,
  • Curbs you could step off of wrong if you were not watching your feet (I partially rolled my left ankle in the first mile, rude awakening. Felt it for the next 10 or so)
  • The warm weather (mid 60s and sunny, the sections in the shade were pretty pleasant but in the sun you cooked!)
I wasn't prepared for this race in general (signed up for it a week or so ago), and wasn't optimistic about even finishing (the last month had seen no runs over about 5 miles). I positioned myself between the 3:40 and 3:50 pace group balloons, figuring I'd start by running 9s.

For the first half (and after my ankle rollover especially) I just hung out with the majority of the runners I was near, running 9s as planned. I didn't see too much passing, but maybe it was subtle? The first half went in just about 2 hours, and a bit after I stopped to stretch a little, massage my right calf (which had been getting tight on longer runs causing tendonitis in my ankle, which is why I hadn't done any long runs in ages), and my left ankle seemed to be fine, so I kept on. Around mile 20 I realized that a) I was going to finish, and b) I was actually feeling pretty good considering (my HR had been 130-140 or so the whole time), so I decided I'd run some 8s when the crowded course allowed and get some of those newfangled negative splits, which was successful.

Other notes:

  • Seeing Al and friends on the course was awesome.
  • Swimming in the harbor after was incredibly cold and perfect and 10/10 would do again.
  • Aid stations have signs ahead of them that say "OPEN BAR 100 meters ahead" which I find hilarious.
  • Aid stations use a ton of plastic cups.
  • I carried a backpack with me which turned out to be handy (extra water, ended up having a liter or so -- the aid stations were few and far between and as a result crowded and difficult.. but even if I stopped and had 2 waters + 1 energy drink at each, I would've still finished very dehydrated).
  • If you (like me) are not too familiar with Copenhagen, you don't really notice the loop in the course, because by the time the second time comes around you're in full "make this shit happen" mode.
  • The dry-bag backpack that they gave everybody is a fantastic perk, especially given how affordable this race is (compared to NY at least!).
  • Copenhagen is really lovely. <3

Video from my sunglasses: (youtube link)

1 Comment


June 10, 2018
plane music in three parts:


Shots from a recent flight, music from the previous session with Andy Omel and Sarai Moore. These are short because I originally uploaded them to Instagram:
(youtube link)

(youtube link)

(youtube link)



Recordings:

Not Vampires - 1 -- [5:02]
Not Vampires - 2 -- [8:39]
Not Vampires - 3 -- [7:35]
Not Vampires - 4 -- [4:46]
Not Vampires - 5 -- [8:17]
Not Vampires - 6 -- [3:24]
Not Vampires - 7 -- [5:17]
Not Vampires - 8 -- [4:34]
Not Vampires - 9 -- [4:35]
Not Vampires - 10 -- [4:33]
Not Vampires - 11 -- [7:25]
Not Vampires - 12 -- [7:56]
Not Vampires - 13 -- [7:56]
Not Vampires - 14 -- [4:22]
Not Vampires - 15 -- [4:16]
Not Vampires - 16 -- [5:42]
Not Vampires - 17 -- [4:26]
Not Vampires - 18 -- [6:39]

Comment...


March 28, 2018
a song, revisited

In 2016 I made this little sketch of a song (bonus trombone in there! woo), now I'm having fun revisiting/expanding it with Andy and Sarai, here's a new live version with re-recorded (and doubled) vocals added, woot. Also, trying to play drums while trying to sing is extra fun.

1 Comment


March 20, 2018
share the function names in your mac programs and plug-ins, man

It is amazing to me how many developers shoot themselves in the foot in the name of secrecy, image, embarrassments, fear of piracy, or something else (I have no idea!).

For example, almost all VST plug-in developers I see will never put symbol names in their plug-ins. So when a plug-in crashes, you get crash traces like this:

0   com.somedev.pluginnamethingy    0x00000001a4d351e3 0x1a4cb7000 + 516579
1   libc++abi.dylib                 0x00007fff76d8c3bb __dynamic_cast + 272
2   com.somedev.pluginnamethingy    0x00000001a505d897 0x1a4cb7000 + 3827863
3   com.somedev.pluginnamethingy    0x00000001a5107d85 0x1a4cb7000 + 4525445
4   com.somedev.pluginnamethingy    0x00000001a5107d15 0x1a4cb7000 + 4525333
5   com.somedev.pluginnamethingy    0x00000001a54740ec 0x1a4cb7000 + 8114412
6   com.somedev.pluginnamethingy    0x00000001a5107d85 0x1a4cb7000 + 4525445
7   com.somedev.pluginnamethingy    0x00000001a5145407 0x1a4cb7000 + 4776967
8   com.somedev.pluginnamethingy    0x00000001a5107d15 0x1a4cb7000 + 4525333
9   com.somedev.pluginnamethingy    0x00000001a5273ac1 0x1a4cb7000 + 6015681
10  com.somedev.pluginnamethingy    0x00000001a5103be4 0x1a4cb7000 + 4508644
Super helpful to everybody involved, right?

In REAPER we have for a very long time, on macOS at least, included symbol names. So when there's a crash, we see:
30  com.apple.AppKit                0x00007fff4f2f2ee6 _NSTryRunModal + 100
31  com.apple.AppKit                0x00007fff4ec5dcf9 -[NSApplication runModalForWindow:] + 133
32  com.cockos.reaper               0x0000000100510cad SWELL_DialogBox(SWELL_DialogResourceIndex*, char const*, 
33  com.cockos.reaper               0x000000010016583b __localizeDialog(void*, char const*, HWND__*, 
34  com.cockos.reaper               0x0000000100149a02 LoadProjectFromContext(ReaProject*, ProjectStateContext*, 
35  com.cockos.reaper               0x0000000100147fcc LoadProject(ReaProject*, char const*, int*, int) + 972
36  com.cockos.reaper               0x00000001000aef49 DoProjectLoad(char const*, bool, int) + 537
37  com.cockos.reaper               0x00000001000acc3d Main_openProject(char const*) + 509
38  com.cockos.reaper               0x0000000100070098 Main_OnCommandEx2(int, int, ReaProject*) + 9160
39  com.cockos.reaper               0x00000001000d3a6f Main_OnCommandEx(int, int, ReaProject*) + 31
40  com.cockos.reaper               0x000000010036198b KBD_OnMainActionEx(int, int, int, int, HWND__*, 
Yes, our functions are named terribly. It's much worse than it looks, even, but at a quick glance we (or our troubleshooting user) can quickly see exactly what the hell is going on.

Can one do this on VC builds (without doing full line numbers, obviously)? I forget...

Recordings:

live solo improv: super8 multichannel

3 Comments


December 31, 2017
super8 new years eve

(youtube link)
until next year, everybody...



Recordings:

live solo improv: super8 nye

1 Comment


October 19, 2017
super8 improv rehearsal

(youtube link)

Recordings:

cant be left alone
say goodbye to yourself
super8_reversion - 1 -- [5:59]
super8_reversion - 2 -- [22:17]

Comment...


May 12, 2017
linux hacking on an ASUS T100TA

I've been working on a REAPER linux port for a few years, on and off, but more intensely the last month or two. It's actually coming along nicely, and it's mostly lot of fun (except for getting clipboard/drag-drop working, ugh that sucked ;). Reinventing the world can be fun, surprisingly.

I've also been a bit frustrated with Windows (that crazy defender/antispyware exploit comes to mind, but also one of my Win10 laptops used to update when I didn't want it to, and now won't update when I do), so I decided to install linux on my T100TA. This is a nice little tablet/laptop hybrid which I got for $200, weighs something like 2 pounds, has a quad core Atom Bay Trail CPU, 64GB of MMC flash, 2GB of RAM, feels like a toy, and has a really outstanding battery life (8 hours easily, doing compiling and whatnot). It's not especially fast, I will concede. Also, I cracked my screen, which prevents me from using the multitouch, but other than that it still works well.

Anyway, linux isn't officially supported on this device, which boots via EFI, but following this guide worked on the first try, though I had to use the audio instructions from here. I installed Ubuntu 17.04 x86_64.

I did all of the workarounds listed, and everything seemed to be working well (lack of suspend/hibernate is an obvious shortcoming, but it booted pretty fast), until the random filesystem errors started happening. I figured out that the errors were occurring on read, the most obvious way to test would be to run:

debsums -c
which will check the md5sum for the various files installed by various packages. If I did this with the default configuration, I would get random files failing. Interestingly, I could md5sum huge files and get consistent (correct results). Strange. So I decided to dig through the kernel driver source, for the first time in many many years.

Workaround 1: boot with:
sdhci.debug_quirks=96
This disables DMA/ADMA transfers, forcing all transfers to use PIO. This solved the problem completely, but lowered the transfer rates down to about (a very painful) 5MB/sec. This allowed me to (slowly) compile kernels for testing (which, using the stock ubuntu kernel configuration, meant a few hours to compile the kernel and the tons and tons of drivers used by it, ouch. Also I forgot to turn off debug symbols so it was extra slow).

I tried a lot of things, disabling various features, getting little bits of progress, but what finally ended up fixing it was totally simple. I'm not sure if it's the correct fix, but since I've added it I've done hours of testing and haven't had any failures, so I'm hoping it's good enough. Workaround 2 (I was testing with 4.11.0):
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2665,6 +2665,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 				 */
 				host->data_early = 1;
 			} else {
+				mdelay(1); // TODO if (host->quirks2 & SDHCI_QUIRK2_SLEEP_AFTER_DMA)
 				sdhci_finish_data(host);
 			}
 		}
Delaying 1ms after each DMA transfer isn't ideal, but typically these transfers are 64k-256k, so it shouldn't cause too many performance issues (changing it to usleep(500) might be worth trying too, but I've recompiled kernel modules and regenerated initrd and rebooted way way too many times these last few days). I still get reads of over 50MB/sec which is fine for my uses.

To be properly added it would need some logic in sdhci-acpi.c to detect the exact chipset/version -- 80860F14:01, not sure how to more-uniquely identify it -- and a new SDHCI_QUIRK2_SLEEP_AFTER_DMA flag in sdhci.h). I'm not sure this is really worth including in the kernel (or indeed if it is even applicable to other T100TAs out there), but if you're finding your disk corrupting on a Bay Trail SDHCI/MMC device, it might help!

6 Comments


February 18, 2017
joining the modern economy

After reading an article on hacker news about distrokid.com, I realized I could put all of my many hundreds of hours of recorded music on Spotify, Apple Music, Google Play, Amazon, etc etc etc. For $20/year. I wouldn't expect to earn any money whatsoever for my recordings, but it would be entertaining.

So, as a result, step 1 of this process is complete -- which is to say that I put together an album from many of my recent Super8/REAPER-produced recordings. 18 of them, to be exact, totalling about 45 minutes of music, with words. Every song has words. As a result, I titled this album "Songs with Words".

This album, which is incredible in the 2017 sense only, is available via Spotify, Apple Music, Google Play, probably others too (search for my name in the respective service) -- and of course it is available for free in streamable/downloadable form via music.1014.org, or here:


More albums will probably soon follow, one or two volumes of instrumentals will be next.



Recordings:

cory_andre_anette_aubrey - 1 -- [3:12]
cory_andre_anette_aubrey - 2 -- [4:01]
cory_andre_anette_aubrey - 3 -- [5:43]
cory_andre_anette_aubrey - 4 -- [6:39]
cory_andre_anette_aubrey - 5 -- [4:05]
cory_andre_anette_aubrey - 6 -- [5:19]
cory_andre_anette_aubrey - 7 -- [4:34]
cory_andre_anette_aubrey - 8 -- [5:16]
cory_andre_anette_aubrey - 9 -- [5:35]
cory_andre_anette_aubrey - 10 -- [4:42]
cory_andre_anette_aubrey - 11 -- [3:13]
cory_andre_anette_aubrey - 12 -- [5:21]
cory_andre_anette_aubrey - 13 -- [5:01]
cory_andre_anette_aubrey - 14 -- [2:59]
cory_andre_anette_aubrey - 15 -- [4:09]
cory_andre_anette_aubrey - 16 -- [6:17]
cory_andre_anette_aubrey - 17 -- [7:37]
cory_andre_anette_aubrey - 18 -- [13:45]

1 Comment


February 2, 2017
macOS screen updating, 2017 edition

TL;DR: Retina iMac (4k/5k) owners can greatly improve the graphics performance of many applications (including REAPER) by setting the color profile (in System Preferences, Displays, Color tab) to "Generic RGB" or "Adobe RGB." (and restarting REAPER and/or other applications being tested)

I previously wrote in mid-2014 about the state of blitting bitmaps to screen on modern OS X (now macOS) versions. Since then, Apple has released new hardware (including Retina iMacs) and a couple of new macOS versions.

Much of that article is still useful today, but I made a mistake in the second update:

    OK, if you provide a bitmap that is twice the size of the drawing rect, you can avoid argb32_image_mark_RGBXX, and get the Retina display to update in about 5-7ms, which is a good improvement (but by no means impressive, given how powerful this machine is). I made a very simple software scaler (that turns each pixel into 4), and it uses very little CPU.
While this was helpful (and did decrease the amount of time spent blitting), it was wrong in that the reason for the faster blit was that the system was parallelizing the blit with multiple cores. So, it was faster, but it also used more CPU (and was generally wasteful).

I discovered this because I've been researching how to improve REAPER's graphic performance on the iMac 5k in particular, so I started benchmarking. This time around, I figured I should measure how many screen pixels are updated and divide that by how long it takes. Some results, based on my memory (I'm not going to rerun them for this article, laziness).

Initial version (REAPER 5.32 state, using the retina hack described above, public WDL as of today):
  • old C2D iMac, 10.6: 350MPix/sec
  • mid-2012 RMBP 15", 10.12, Thunderbolt display (non-retina): 1500MPix/sec
  • mid-2012 RMBP 15", 10.12, built-in display (retina): 800MPix/sec
  • late-2015 Retina iMac 5k, 10.12: 192MPix/sec
The one that really jumped out at me was the Retina iMac 5k -- it's a quarter of the speed of the RMBP! WTF. We'll get to that later.

After I realized the hack above was actually doing more work (thank you, Xcode instrumentation), I did some more experiments, avoiding the hack, and found that in the newer SDKs there are kCGImageByteOrderXYZ flags (I don't believe it was in previous SDKs), and found that these alised to KCGBitmapByteOrderXYZ, and that when using kCGBitmapByteOrder32Host with the pixel format for CGImageCreate()/etc, it would speed things up. With retina hack removed:
  • mid-2012 RMBP 15", 10.12, built-in display (retina): 300MPix/sec
  • late-2015 Retina iMac 5k, 10.12: 152MPix/sec
With retina hack removed and byte order set to host:
  • old C2D iMac, 10.6: 350MPix/sec
  • mid-2012 RMBP 15", 10.12, Thunderbolt display (non-retina): 1500MPix/sec
  • mid-2012 RMBP 15", 10.12, built-in display (retina): 720MPix/sec
  • late-2015 Retina iMac 5k, 10.12: 200MPix/sec
The non-retina displays might have changed slightly, but it was insignificant. So, by setting the byte order to native, we get the Retina MBP close to the level of performance of the hack, which isn't great but is serviceable, and at least the CPU use is decreased. This also has the benefit (drawback?) of making the byte-order of pixels the same on macOS/Intel and win32, which will take some more attention (and a lot of testing).

From profiling and looking at the code, this blit performance could easily be improved by Apple -- the inner loop where most time is being spent does a lot more than it needs to. Come on Apple, make us happy. Details offered on request.

Of course, this really doesn't do anything for the iMac 5k -- 200MPix/sec is *TERRIBLE*. The full screen is 15 megapixels, so at most that gets you around 13fps, and that's at 100% CPU use. After some more profiling, I found that the function chewing the most CPU ended in "64". Then it hit me -- was this display running in 16 bits per channel? A quick google search later, it was clear: the Retina iMacs have 10-bit displays, and you can run them in 10 bits per channel, which means 64 bits per pixel. macOS is converting all of our pixels to 64 bits per pixel (I should also mention that it seems to be doing a very slow job of it). Luckily, changing the color profile (in system preferences, displays) to "Generic RGB" or similar disables this, and it gets the ~800MPix/sec level of performance similar to the RMBP, which is at least tolerable.

Sorry for the long wordy mess above, I'm posting it here so that google finds it and anybody looking into why their software is slow on macOS 10.11 or 10.12 on retina imacs have some explanation.

Also please please please Apple optimize CGContextDrawImage()! I'm drawing an image with no alpha channel and no interpolation and no blend mode and the inner loop is checking each pixel to see if the alpha is 255? I mean wtf. You can do better. Hell, you've done way better. All that "new" Retina code needs optimizing!

Update a few hours later:
Fixing various issues with the updated byte-ordering, CoreText produces quite different output for CGBitmapContexts created with different byte orderings:


Hmph! Not sure which one is "correct" there... hmm... If you use kCGImageAlphaPremultipliedFirst for the CGBitmapContext rather than kCGImageAlphaNoneFirst, then it looks closer to the original, maybe. ?

Also other caveat: NSBitmapImageRep can't seem to deal with the ARGB format either, so if you use that you need to manually bswap the pixels...

Update (2019): SolvedWorked around most of this issue by using Metal, read here.

4 Comments


July 2, 2014
This is 2014 backwards: OSX blit performance

I've been investigating, once again, the performance of drawing code-rendered RGBA bitmaps to NSViews in OSX. I found that on my Retina Macbook Pro (when the application was not in low-resolution legacy mode), calling CGContextSetInterpolationQuality with kCGInterpolationNone would cause CGContextDrawImage() to be more than twice as fast (with less filtering of the image, which was a fair tradeoff and often desired).

The above performance gain aside, I am still not satisfied with the bitmap drawing performance on recent OSX versions, which has led me to benchmark SWELL's blitting code. My test uses the LICE test application, with a screen full of lines, an opaque NSView, and 720x500 resolution.

OSX 10.6 vs 10.8 on a C2D iMac

My (C2D 2.93GHz) iMac running 10.6 easily runs the benchmark at close to 60 FPS, using about 45% of one core, with the BitBlt() call typically taking 1ms for each frame.

Here is a profile -- note that CGContextDrawImage() accounts for a modest 3.9% of the total CPU use:


It might be possible to reduce the work required by changing our bitmap representation from ABGR to RGBA (avoiding sseCGSConvertXXXX8888TransposeMask and performing a memcpy() instead), but in my opinion 1ms for a good sized blit (and less than 4% of total CPU time for this demo) is totally acceptable.

I then rebooted the C2D iMac into OSX 10.8 (Mountain Lion) for a similar test.

Running the same benchmark on the same hardware in Mountain Lion, we see that each call to BitBlt() takes over 6ms, the application struggles to exceed 57 FPS, and the CPU usage is much higher, at about 73% of a core.

Here is the time sampling of the CGContextDrawImage() -- in this case it accounts for 36% of the total CPU use!


Looking at the difference between these functions, it is obvious where most of the additional processing takes place -- within img_colormatch_read and CGColorTransformConvertData, where it apparently applies color matching transformations.

I'm happy that Apple cares about color matching, but to force it on (without allowing developers control over it) is wasteful. I'd much rather have the ability transform the colors before rendering, and be able to quickly blit to screen, than to have to have every single pixel pushed to the screen color transformed. There may be some magical way to pass the right colorspace value to CGCreateImage() to bypass this, but I have not found it yet (and I have spent a great deal of time looking, and trying things like querying the monitor's colorspace).

That's what OpenGL is for!
But wait, you say -- the preferred way to quickly draw to screen is OpenGL.

Updating a complex project to use OpenGL would be a lot of work, but for this test project I did implement a very naive OpenGL blit, which enabled an OpenGL context for the view and created a texture for drawing each frame, more or less like:

    glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_RECTANGLE_EXT);

    GLuint texid=0;
    glGenTextures(1, &texid);
    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texid);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, sw);
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER,  GL_LINEAR);
    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT,0,GL_RGBA8,w,h,0,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8, p);

    glBegin(GL_QUADS);

    glTexCoord2f(0.0f, 0.0f);
    glVertex2f(-1,1);
    glTexCoord2f(0.0f, h);
    glVertex2f(-1,-1);
    glTexCoord2f(w,h);
    glVertex2f(1,-1);
    glTexCoord2f(w, 0.0f);
    glVertex2f(1,1);

    glEnd();

    glDeleteTextures(1,&texid);
    glFlush();
This resulted in better performance on OSX 10.8, each BitBlt() taking about 3ms, framerate increasing to 58, and the CPU use going down to about 50% of a core. It's an improvement over CoreGraphics, but still not as fast as CoreGraphics on 10.6.

The memory use when using OpenGL blitting increased by about 10MB, which may not sound like much, but if you are drawing to many views, the RAM use would potentially increase with each view.

I also tested the OpenGL implementation on 10.6, but it was significantly slower than CoreGraphics: 3ms per frame, nearly 60 FPS but CPU use was 60% of a core, so if you do ever implement OpenGL blitting, you will probably want to disable it for 10.6 and earlier.

Core 2 Duo?! That's ancient, get a new computer!
After testing on the C2D, I moved back to my modern quad-core i7 Retina Macbook Pro running 10.9 (Mavericks) and did some similar tests.

  • Normal: 12-14ms per frame, 46 FPS, 70% of a core CPU use
  • Normal, in "Low Resolution" mode: 6-7ms per frame, 58FPS, 60% of a core CPU use
  • Normal, without the kCGInterpolationNone: 29ms per frame, 29 FPS, 70% of a core CPU use
  • Normal, in "Low Resolution" mode, without kCGInterpolationNone: same as with kCGInterpolationNone.
  • GL: 1-2ms per frame, 57 FPS, 37% of a core CPU
  • GL, in "Low Resolution" mode: 1-2ms per frame, 57 FPS, 40% of a core CPU
Interestingly, "Low Resolution" mode is faster in all modes except for GL, where apparently it is slower (I'm guessing because the hardware accelerates the GL scaling, whereas "Low Resolution" mode puts it through a software-scaler at the end.

Let's see where the time is spent in the "Normal, Low Resolution" mode:

This looks very similar to the 10.8, non-retina rendering, though some function names have changed. There is the familiar img_colormatch_read/CGColorTransformConvertData call which is eating a good chunk of CPU. The ripc_RenderImage/ripd_Mark/argb32_image stack is similar to 10.8, and reasonable in CPU cycles consumed.

Looking at the Low Resolution mode, it really does behave similar to that of 10.8 (though it's depressing to see that it still takes as long to run on an i7 as 10.8 did on a C2D, hmm). Let's look at the full-resolution Retina mode:

img_colormatch_read is present once again, but what's new is that ripc_RenderImage/ripd_Mark/argb32_image have a new implementation, calling argb32_image_mark_RGB24 -- and argb32_image_mark_RGB24 is a beast! It uses more CPU than just about anything else. What is going on there?

Conclusions
If you ever feel as if modern OSX versions have gotten slower when it comes to updating the screen, you would be right. The basic method of drawing ixels rendered in a platform-independent fashion to screen has gotten significantly slower since Snow Leopard, most likely in the name of color-accuracy. In my opinion this is an oversight on Apple's part, and they should extend the CoreGraphics APIs to allow manual application of color correction.

Additionally, I'm suspicious that something odd is going on within the function argb32_image_mark_RGB24, which appears to only be used on Retina displays, and that the performance of that function should be evaluated. Improving the efficiency of that function would have a positive impact on the performance of many third party applications (including REAPER).

If anybody has an interest in duplicating these results or doing further testing, I have pushed the updates to the LICE test application to our WDL git repository (see WDL/lice/test/).

Update: July 3, 2014
After some more work, I've managed to get the CPU use down to a respectable level in non-Retina mode (10.8 on the iMac, 10.9/Low Resolution on the Retina MBP), by using the system monitor's colorspace:

    CMProfileRef systemMonitorProfile = NULL;
    CMError getProfileErr = CMGetSystemProfile(&systemMonitorProfile);
    if(noErr == getProfileErr)
    {
      cs = CGColorSpaceCreateWithPlatformColorSpace(systemMonitorProfile);
      CMCloseProfile(systemMonitorProfile);
    }
Using this colorspace with CGContextCreateImage prevents CGContextDrawImage from calling img_colormatch_read/CGColorTransformConvertData/etc. On the C2D 10.8, it gets it down to 1-2ms per frame, which is reasonable.

However, this mode is appears to be slower on the Retina MBP in high resolution mode, as it calls argb32_image_mark_RGB32 instead of argb32_image_mark_RGB24 (presumably operating on my buffer directly rather than the intermediate colorspace-converted buffer), which is even slower.

Update: July 3, 2014, later
OK, if you provide a bitmap that is twice the size of the drawing rect, you can avoid argb32_image_mark_RGBXX, and get the Retina display to update in about 5-7ms, which is a good improvement (but by no means impressive, given how powerful this machine is). I made a very simple software scaler (that turns each pixel into 4), and it uses very little CPU. So this is acceptable as a workaround (though Apple should really optimize their implementation). We're at least around 6ms, which is way better than 12-14ms (or 29ms which is where we were last week!), but there's no reason this can't be faster. Update (2017): the mentioned method was only "faster" because it triggered multiprocessing, see this new post for more information.

As a nice side effect, I'm adding SWELL_IsRetinaDC(), so we can start making some things Retina aware -- JSFX GUIs would be a good place to start...

5 Comments


December 14, 2013
a month later, midi2osc becomes OSCII-bot

midi2osc, as mentioned in the last post, got some updates which made its name obsolete, particularly the ability to send MIDI and receive OSC, so it has now been renamed OSCII-bot. Other mildly interesting updates:

  • OSX version
  • Can load multiple scripts, which run independently but can share hardware
  • Better string syntax (normal quotes rather than silly {} etc), user strings identified by values 0..1023
  • Better string manipulation APIs (sprintf(), strcpy(), match(), etc).
  • match() and oscmatch(), which can be used for simple regular expressions with the ability to extract values
  • Ability to detect stale devices and reopen them
  • Scripts can output text to the newly resizeable console, including basic terminal emualtion (\r, and \33[2J for clear)
  • Vastly improved icon
I'll probably get around to putting it on cockos.com soon enough, but for now a new build is here. Read the readme.txt before using for instructions.

The thing I'm most excited about, in this, is the creation of eel_strings.h, which is a framework for extending EEL2 (the scripting engine that powers JSFX, for one) to add string support. Adding support for strings to JSFX will be pretty straightforward, so we'll likely be doing that in the next few weeks. Fun stuff. Very few things are as satisfying as making fun programming languages to use...

8 Comments


November 14, 2013
another quick project - Cockos midi2osc

Making installers and web pages is too much of a pain for a small project, so:

Here's another project, this one took less than 24 hours to make. It's a little win32 program called "midi2osc" (license: GPL, binary included, code requires WDL to compile), and it simply listens to any number of MIDI devices, and broadcasts to any number of destinations via OSC-over-UDP.

MIDI and OSC use completely different types of encoding -- MIDI consists of 1-3 byte sequences (excluding sysex), and OSC is encoded as a string and any number of values (strings, floats, integers, whatever). It would be very easy to make a simplistic conversion of every MIDI event, such as 90 53 7f being converted to "/note/on/53" with an integer value of 7f, and so on. This would be useful, but also might be somewhat limited.

In order to make this as useful as possible, I made it use EEL2 to enable user scripting of events. EEL2 is a fast scripting engine designed for floating point computation, that was originally developed as part of Nullsoft AVS, and evolved as part of our Jesusonic/JSFX code. EEL2 compiles extremely quickly to native code, and can have context that is used by code running in multiple threads simultaneously.

For this project the EEL2 syntax was extended slightly, via the use of a preprocessor, so that you can specify format strings for OSC. For example, you can tell REAPER to set a track's volume via:

    oscfmt0 = trackindex;
    oscsend(destination, { "/track/%.0f/volume" }, 0.5);
Internally, { xyz } is stored to a string table and inserted as a magic number which refers to that string table entry. It is cheap, but it works.

Other than that pretty much everything else was a matter of copying and pasting some tedious bits (win32 MIDI device input, OSC message construction and bundling) and writing small bits of glue.

Since writing this, I've found myself fixing a lot of small OSC issues in REAPER. I always tell people how using the thing you make is very important -- I should update that to include the necessity of having good test environments (plural).

Why did I make this? My Zoom R24. This is a great device, but the Windows 7/64 driver has some issues. Particularly:
  • If the MIDI input device of the R24 is not opened, audio playback is not reliable. This includes when listening to Winamp or watching YouTube. So basically, for this thing to be useful, I need something to keep hitting the MIDI device constantly. So for you Zoom R24 win64 users who have this problem, midi2osc might be able to fix your problems.
  • If REAPER crashes or is otherwise debugged with the MIDI device open, the process hangs and it's a pain to continue. Moving the MIDI control to a separate process that can run in the system tray = win.
  • (not midi2osc related): I wish the drum pads would send MIDI too... *ahem*
As a result of this, the midi2osc.cfg that comes in the .zip represents basic support for the R24:
// @input lines:
// usage: @input devicenameforcode "substring match" [skip]
// can use any number of inputs. devicenameforcode must be unique, if you specify multiple @input lines
// with common devicenameforcode, it will use the first successful line and ignore subsequent lines with that name
// you can use any number of devices, too

@input r24 "ZOOM R"


// @output lines
// usage: @output devicenameforcode "127.0.0.1:8000" [maxpacketsize] [sleepamt]
// maxpacketsize is 1024 by default, can lower or raise depending on network considerations
// sleepamt is 10 by default, sleeps for this many milliseconds after each packet. can be 0 for no sleep.

@output localhost "127.0.0.1:8000"

@init

// called at init-time
destdevice = localhost; // can also be -1 for broadcast

// 0= simplistic /track/x/volume, /master/volume
// 1= /r24/rawfaderXX (00-09)
// 2= /action/XY/cc/soft (tracks 1-8), master goes to /r24/rawfader09
fader_mode=2;

@timer

// called around 100Hz, after each block of @msg

@msg

// special variables:
// time (seconds)
// msg1, msg2, msg3 (midi message bytes)
// msgdev == r24  // can check which device, if we care

(msg1&0xf0) == 0xe0 ? (

  // using this to learn for monitoring fx, rather than master track
  fader_mode > 0 ? (
     fmtstr = { f/r24/rawfader%02.0f }; // raw fader
     oscfmt0 = (msg1&0xf)+1;

     fader_mode > 1 && oscfmt0 != 9 ? (
       fmtstr = { f/action/%.0f/cc/soft }; // this is soft-takeover, track 01-08 volume
       oscfmt0 = ((oscfmt0-1) * 8) + 20;
     );

     val=(msg2 + (msg3*128))/16383;
     val=val^0.75;
     oscsend(destdevice,fmtstr,val);
  ) : (
     fmtstr = (msg1&0xf) == 8 ? { f/master/volume } : { "f/track/%.0f/volume"};
     oscfmt0 = (msg1&0xf)+1;
     oscsend(destdevice,fmtstr,(msg2 + (msg3*128))/16383);
  );
);

msg1 == 0x90 ? (
  msg2 == 0x5b ? oscsend(destdevice, { b/rewind }, msg3>64);
  msg2 == 0x5c ? oscsend(destdevice, { b/forward }, msg3>64);

  msg3>64 ? (
    oscfmt0 = (msg2&7) + 1;

    msg2 < 8 ?  oscsend(destdevice, { t/track/%.0f/recarm/toggle }, 0) :
      msg2 < 16 ?  oscsend(destdevice, { t/track/%.0f/solo/toggle }, 0) :
        msg2 < 24 ?  oscsend(destdevice, { t/track/%.0f/mute/toggle }, 0) : 
    (
      msg2 == 0x5e ? oscsend(destdevice, { b/play }, 1);
      msg2 == 0x5d ? oscsend(destdevice, { b/stop }, 1);
      msg2 == 0x5f ? oscsend(destdevice, { b/record }, 1);
    )
  );
);

msg1 == 0xb0 ? (
  msg2 == 0x3c ? (
    oscsend(destdevice, { f/action/992/cc/relative }, ((msg3&0x40) ? -1 : 1));
  );

);
The 9th fader sends "/r24/rawfader09" because I have that OSC string mapped (with soft-takeover) to a volume plug-in in my monitoring FX chain.

6 Comments


July 18, 2013
HTML5 canvas/javascript fun #2

a little more wankage, reliving my highschool days



Recordings:

kawha

7 Comments


July 2, 2013
HTML5 canvas/javascript fun #1




Recordings:

chillstache

1 Comment


June 17, 2013
Citibike NYC

I'm a fan of bicycling, and the launch of Citi Bike here in New York is something I am still quite excited about! While the launch has had its share of glitches, it's really shaping up. Their blog has been giving daily statistics, and I thought I'd put them in a spreadsheet to see if anything interesting could be made. I've made the spreadsheet public in Google Docs in case anybody wants to do some additional analysis.

Some initial comments on the data:

  • The average speed is calculated based on the total mileage counter, trip count, and average trip duration. After the first few days (whose data is a bit all over the place), it settles in at about 7.4-7.5 MPH. Do we think that their distance calculation is A) as the bird flies, B) bird-distance * cityadjustmentfactor, or C) they route most likely route in google maps? Probably safe to rule out C, and given the top speed of these things is probably around 15MPH, I'd say it's probably B (some 1.3x cityadjustmentfactor, or something).
  • If we assume that the last 5 days worth of data on day and week passes hold steady (I know, unlikely, as factors such as season, initial buzz, conversion to annual members, and so on will affect things greatly), these will bring in $9.3 million and $2.2 million per year respectively.
  • If annual members top out at 80,000 (a little under twice what it is now, I would say this is very conservative), that'll be around $7.6 million per year.
  • It becomes apparent why they are called "Citibike" and also have Mastercard logos on them (as they ponied up something like $41 million and $6 million respectively -- I wonder if this is one time or per year).
  • Hopefully annual membership will continue to grow well past 80,000, though, and presumably there will be extra revenue from late fees...
  • I wonder what their operating budget is...
  • OK discussions of money are sort of a bummer (not because of whether this is feasible or not, but just because talking about money makes me uncomfortable): the average trip length of 2-3 miles is pleasing.. 2 miles in a long way in Manhattan, glad to see people are making good use of the bikes!
On an unrelated-to-citibike-data-note, it is also humbling to see that even when CitiBikes are being used in record numbers, they are still far, far outnumbered by normal bicycles. Anyhoo..

If anybody makes any interesting graphs or correlations or extrapolations with that data, post 'em (or links) in the comments...

5 Comments


March 27, 2013
REAPER development fun

Using stuff coming in the next release (though it is not obvious what that stuff is, aside from webm encoding, due to the nature of it, but I didn't play it nearly this well live, and of course it only took a handful of minutes of recording and couple hours to do start to finish):


2 Comments


July 14, 2011
Fun with denormals

Something that often comes up when writing audio applications are things called "denormals". These are floating point numbers that are very small, so small in fact that for some reason CPU designers think they are quite rare (OK so they are), so the circuitry that processes them is very slow, when compared to that of a "normal" sized number.

If you read that (awful) explanation, and didn't understand it or care, I apologize, you can stop reading now because it will only get more boring and less intelligible.

We have made some common code to filter out these numbers, as many others no doubt have done:

// boring code omitted, see WDL/denormal.h for the full code
// WDL_DENORMAL_DOUBLE_HW() is a macro which safely gets you the high 32 bits of a double as an unsigned int.

static double WDL_DENORMAL_INLINE denormal_filter_double(double a)
{
  return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
}
The above code pretty simply looks at the exponent field of the double, and if it is nonzero, returns the double, otherwise it returns 0.

Recently it came to our attention that we actually needed to filter out larger numbers as well (when sending those numbers through a process such as a FFT, they would end up as denormals). If we pick a number around 10^-16 (not being picky about the exact cutoff), which has an exponent of 0x3C9, we can choose to filter when the expoenent field is under that value:
static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a)
{
  return ((WDL_DENORMAL_DOUBLE_HW(&a))&0x7ff00000) >= 0x3c900000 ? a : 0.0;
}
That was pretty much free (ok slightly larger code, I suppose). One nice thing that became apparent was that we could filter NaN and infinity values this way as well (exponent == 0x7FF), with only the cost of a single integer addition:
static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a)
{
  return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= 0x3cA00000 ? a : 0.0;
}
Note that the exponent is increased by 1, so that 0x7FF becomes 0, and we adjusted the cutoff constant for the change.

An extra thought: if you need to pick the cutoff number more precisely, you could change the mask to 0x7fffffff and the cutoff (0x3cA00000) to include some of the fraction digits...

Additional reading: IEEE_754-1985.

Oh and happy bastille day!

3 Comments


April 19, 2011
tame impala

I love these guys, I can't wait until next week for their show. Anyway some of their (old?) demos/unreleased tracks have shown up on youtube, and are really wonderful. Such low quality and such good result. Here's a little playlist of some of them I put together:


Also, I would highly recommend their album "Innerspeaker", as well as the EP that has the song "half full glass of wine" on it. Both of those are outstanding.

Recordings:

freeform jam with louie

4 Comments


December 19, 2010
Joy, from Perl

I've recently started using Perl for text wrangling instead of PHP -- it started after much of my PHP included a lot of preg_replace and preg_match calls, which got me wondering...

There's a certain satisfaction I get from perl that I don't really get from other languages. There's something about the density that makes it quite readable, at least for the author. Here's a script I wrote to automatically add a new build configuration, based on an existing build configuration, with some modifications, to a given .dsp (VC6 project file):

    
    #!/usr/bin/perl
    $sp = "Win32 Release";
    $np = "Win32 Nitpicker";
    $spd="Release";
    $npd="Nitpicker";
    $spdir="/Release/";
    $npdir="/Nitpicker/";
    $libfile = "../../nitpicker/libcmt_nitpick.lib";
    while (<>)
    {
      chomp;
      s/\r$//;
      s/\n$//;
       
    
      print $_ . "\r\n";
      if (/^!ELSEIF .*$sp".*$/ || /^!IF .*$sp".*$/)
      {
        s/^!IF/!ELSEIF/;
        s/$sp/$np/;
        @nc = ($_);
        while (<>)
        {
          chomp;
          s/\r$//;
          s/\n$//;
          if (/^!/)
          {
            my $tmp=$_;
            foreach (@nc)
            {
    	  s/$spd/$npd/g;
    	  s/$spdir/$npdir/g;
    	  if (/^# ADD BASE CPP/)
    	  {
    	    s/\/Z\S *//;
    	    s/\/YX *//;
    	    s/\/FR *//;
    	    s/\/FD *//;
    	    s/$/ \/FR \/FD \/Zi/;
    	  }
              if (/^# ADD CPP/)
    	  {
    	    s/\/Z\S *//;
    	    s/\/M\S *//;
    	    s/\/O\S *//;
    	    s/\/FR *//;
    	    s/\/FD *//;
    	    s/$/ \/FR \/FD \/Zi \/MT \/Ot \/Og \/D "DEBUG_TIGHT_ALLOC"/;
    	  }
    	  if (/^# ADD LINK32/)
    	  {
    	    s/^# ADD LINK32 /# ADD LINK32 $libfile /;
    	    s/\/debug *//;
    	    s/\/out:/\/nodefaultlib:"LIBCMT" \/out:/;
    	    s/$/ \/debug/;
    	  }
    	  if (/^# ADD BASE LINK32/)
    	  {
    	    s/\/debug *//;
    	    s/\/map *//;
    	    s/\/dll /\/dll \/debug /;
    	    s/$/ \/fixed:no/;
    	  }
              print $_ . "\r\n";
            }
            print $tmp;
            last;
          }
          print $_ . "\r\n";
          push(@nc,$_);
        }
      }
      if (/^!MESSAGE.*$sp".*$/ || /^# Name ".*$sp" *$/)
      {
        s/$sp/$np/;
        print $_ . "\r\n";
      }
    }
    
In case anybody is interested, Nitpicker is something we've been working on that is similar to Electric Fence or other memory debuggers, but better suited for our workflow/design/etc. We'll probably GPL it once it matures.

6 Comments


July 13, 2010
Buggy fmod() with Visual C++ 2005/2008 targeting x64

I am posting this in case anybody debugging something needs to find it -- I did find mention of it on some Java related site, but nothing conclusive. This may affect VC2010, too, but I haven't tested it.

While VC 2005/2008 targeting x64 generates SSE code for floating point code, fmod() still uses the x87 FPU, and more importantly it assumes that the divide by 0 exception flag is clear going in (meaning if it is set prior to the call, the call will throw an exception or return #.IND regardless of the input). Apparently they assume that since the compiler won't possibly generate code that would cause the divide by 0 floating point exception flag to be set, then it would safe to assume that flag will always be clear. Or it could be a typo. If you use assembly code, or load a module compiled with another compiler that generates x87 code, this can be a huge problem.

Take this example (hi.cpp):

#include <stdio.h>
#include <math.h>

extern "C" void asmfunc();

int main() {
  asmfunc();
  printf("%f\n",fmod(1.0,2.0));
  return 0;
}

and hihi.asm (compile with nasm -f win64):

SECTION .text

global asmfunc
asmfunc:
  fld1
  fldz
  fdivp
  fstp st0
  ret

Compiling this (cl.exe hi.cpp hihi.obj) and running it does not print 1.0, as it should.

The solution we use is to call 'fclex' after any code that might use the FPU. Or not use fmod(). Or call fclex before fmod() every time. I should note that if you use ICC with VC200x, it doesn't have this problem (it presumably has a faster, correct fmod() implementation).

6 Comments


June 7, 2010
LICEcap!

We've just released a new piece of open source software for Windows, called LICEcap! It allows one to create animated screen captures. I know, there's a lot of software out there that does this already, but none of them are both free and meet my needs, so we made LICEcap.

LICEcap has a nice UI (in that you position/size the window where you want to capture, and can move it around while recording). We support writing to .GIF directly (big thanks/credit/blame to Schwa for getting the palette generation working as well as it does), as well as to a new format called .LCF.

LCF compresses by taking a series of frames, say, 20 frames, and then dividing each frame into slices, approx 128x16px each. Each slice is then compared to the same slice on the previous frame, and (if different) encoded directly after the previous frame. zlib is used to remove redundancy (often slices don't completely change from frame to frame, i.e. scrolls or small updates will compress very well). This is all done in 16bpp, and the end result is quite good compression, and lossless (well, 16bpp lossless) quality. REAPER supports playing back the .LCF files, too. The biggest down side is high memory use during compression/decompression (20 frames of 640x480x16bpp is about 12MB, and for smooth CPU distribution you end up using twice that).

I should mention that the primary reason for us making this tool was the desire to post animated gifs of new features in REAPER with the changelog. Hopefully we'll follow through on that.

On a related note, tomorrow (or soonish), I plan to post my latest additions on how to make OS X applications not perform terribly (new one: avoid avoid AVOID CGBitmapContextCreateImage() like the plague. HOLY CRAP it is bad to use). Apple: please, for the love of God, either make your documentation a Wiki, or hire someone who actually writes (multi-platform) applications with your APIs to write documentation.

9 Comments


March 4, 2010
eeePC 901

I got a while back this ASUS eeePC 901, with a 1.6ghz Atom and 20GB of SSD. When I first got it I upgraded the RAM to 2GB, and installed Windows XP. It wasn't that great, so then I tried Win7 pro on it, which almost worked, but would just freeze for lengths of time for no apparent reason. The keyboard is tiny and has a very different arrangement from what I'm used to. It sat idle for a while, and since I have been developing on Linux (hello, SWELL/generic), I decided to install Ubuntu on it. The new verdict:

I love it. It's reasonably fast for compiling, installing new stuff is easy (apt-get ftw), Firefox w/ flash is fine, Xchat is decent enough, the stock mail client is very usable. The best part is that the battery life is fantastic, the screen is bright, there are very little moving parts, and it feels really solid. Yes, a bit like a toy, but I'm not worried about breaking it. Anyway, I'm fully on board with the netbook thing. Maybe next time I'd get one with a slightly larger keyboard, though...

Oh yeah and the other part of what I'm saying is: I'm definitely appreciating where Linux distributions for the desktop have gotten. Almost there... ;)

March 4, 2010
which reminds me: strict aliasing


I get that the "strict aliasing" optimization of recent C/C++ standards allow for great optimization. And I get that gcc has some anciently-designed optimizing, but at any rate, it annoys me that gcc will detect strict-aliasing violating code, and still go ahead and generate code that is obviously wrong -- i.e. when it knows that two pointers ARE in fact pointing to the same memory, it assumes that they can't possibly, and optimizes as if they don't. LLVM probably doesn't have the same problem, heh. Oh well I'll use -fno-strict-aliasing and meanwhile go through and use unions (and occasionally C++ templates) to make our stuff compatible with strict aliasing optimizations.

Of course, on performance sensitive code this is a huge time sink -- I ended up (on our anti-denormal code) looking at the output of many iterations of the same code on gcc i686, x86_64, vc6+icc10, vc2005+icc10, icc11 on osx, gcc ppc, etc, to try to find source code that worked properly and produced decent assembly code. The variety of code produced by each combination is staggering. Also, I found that often the code I thought would be fastest was not, when benchmarked. Oh well.



9 Comments


February 4, 2010
The mighty iPhone vs the Nokia n900

After seeing a slashdot post about people running OS X on the Nokia n900, I read some more info about the n900. It seemed like great hardware, and was debian-linux based, so it seemed like a good platform to play with. Enticed, I found it on Nokia's site, complete with a 14 day return policy.

I should mention, I have/use an iPhone 3GS. Apple ends up pissing me off to no end, but I really end up liking the 3GS. It's a great phone/browser/apprunner/notetaker/calendar/ipod/etc. If it wasn't locked down so tight, I would like it even more. So really I end up disliking the idea of the iPhone, but liking it in reality.

The n900 is pretty much the opposite -- the idea is great. Having a phone I can ssh into and install g++ and make on and build stuff and run on, is great. On paper, everything's there. This is what I found:

  • Screen: the screen looks good. It's high resolution, but the touch sensitivity of it isn't great, it ends up feeling clunky.
  • Storage: on paper it has 32GB of flash. This is great. What's stupid is that the root fs is only 256mb of NAND memory, and while you can install extra packages via apt-get etc, if those packages aren't carefully designed, it ends up filling your root filesystem. Even the obvious things like making /var/cache/apt point to the big disk, they could do, but haven't. So basically you have to do one of many hacks if you wish to install much. The biggest thing I found was moving various /usr/[share|lib|bin]/xxx directories -- all stuff nonessential to booting -- to the bigger disk and symlinking them. Anyway, it's dumb that you should have to do this. Complete pain in the ass. I eventually got everything I wanted installed, but if the point is to have an open extensible phone, you gotta make it do that out of the box.
  • WiFi: support seems solid. When the phone is sleeping, you can still ssh to the phone (if you installed OpenSSH, which is easy). RAD.
  • SSH: awesome. Fast, the thing really feels quick. It is 600mhz, and for command line linux that is super fast. I remember my P133 being quick, too.
  • Web: the browser is pretty solid, and flash support kinda works (wasn't really fast enough for YouTube, but there seems to be an app for this).
  • Keyboard is usable. Better than the iphone's, for me, but not fantastic either.
  • No AT&T 3G support. I don't care whose fault it is, but come on?!.
  • Camera: quality was decent. The video recording was pretty good, sound seemed better than the iPhone 3GS's. Here's a youtube video we did as a test (apologies for the content).
  • General UI: Some things are super fancy (nice blurs, transitions), but other things are not even half baked. There's a nice standard for "close window" or "go back" button locations, but 90% of the time the buttons for those are not visible, yet if you click them they are there. Silly stuff.
  • Multitasking. Mmmm. so good. I like. Hear that, Apple? It's not even a pad...
So I sent the thing back. It didn't last 24 hours. The dealing with root fs, I could get past that. The lack of AT&T 3G support, that made the decision easier. I really tried. I wanted to like it.

6 Comments


December 19, 2009
xmas

I wish I could provide as good a present to the world this Christmas as this:

Jason Lytle's "Merry Xmas 2009" :)

I'm listening now, very happily.

Edit: updated the URL. mmm I cant wait for his next album too.

2 Comments


October 25, 2008
ah, 1997. or: nostalgia

So in 1996 and 1997 I wrote a 3D library called Plush. Here is a screenshot from then:

It was written in C, it tried to be very portable (reading through it now, I'd say almost to a fault -- kinda annoying ;). There were some nifty things about it:

  • 256 color output with adaptive palette creation and management
  • multiple light sources
  • piecewise linear perspective corrected texture mapping
  • Gouraud shading with color ramps that let you do fakePhong
  • optional Z-buffering
  • environment mapping
  • object hierarchies
  • frustum clipping
  • cameras
  • splines
  • matrix functions
  • primitive generation
  • very basic translucency
Totally useless today. But it would run SO fast with 20x the power available...

The code itself wasn't too bad, some stuff that I had spent ages tweaking and getting to run smoothly would surely be reusable.

So in about 8 hours of work I transformed it into Plush2, which is similar to the above, except simplified in C++, renders to 32 bit per pixel output, integrates with our LICE compositing engine, and supports the following new features:

  • 24 bit color output
  • multiple COLORED light sources
  • Texture mapping (piecewise linear perspective corrected) with optional BILINEAR filtering and support for any sized texture, support for texture transparency.
  • Colored Gouraud shading
  • Z-buffering
  • True surface transparency support
  • Multitexture support (one or both textures can be used as environment maps)
  • Full control over how pixels are combined at render -- add, mulitply are supported replace, all with alpha control.
  • No limits on number of light sources, triangles, etc.
A screenshot:

Yes yes I know 3D stuff has all been done a ton, just thought it was interesting bringing things back from the dead to see what would be reusable. Now I'm going to go hug my 2.4ghz multicore processor.

This will be a part of the next WDL release, in case anybody cares, ha ha. It does compile down to pretty small (though not small enough to go making a 4k demo with it)



9 Comments


October 1, 2008
stumbling in code

So while playing with some code to model a resonating spring (F=-k*pos), I discovered that the model I was using produced a very good sine wave approximation. This isn't normally something terribly interesting, as you can approximate sine/cosines very easily, but it was actually quite low complexity -- an iterative approximation with only 2 multiplies and 3 adds per sample. It can also generate the cos() (well, a 90 degree shifted signal) for each point for just one additional multiply.

The error is pretty low for the first few cycles, though after a bit it does drift in relation to the correct wave. I'm not going to spend too much more time on this, but if anybody wants to see if there's some way to correct it, go for it (it may just be rounding error, though, of course).

Here is the code:

    // setup:
    double cos_sc = PI/period_samples; // PI/n for a period of n
    double pos=0; // actually sin(initial_state), 1 for cos(), 0 for sin()
    double vel=1/cos_sc; // actually cos(initial_state)/cos_sc, 0 for cos(),1/cos_sc for sin()
    double tmp = cos_sc*cos_sc;
    double tmp2 = 1.0/(1.0+tmp);
    double mul1 = (1.0-tmp)*tmp2;
    double mul2 = tmp*2.0*tmp2;

    // per-sample calculation
    double output_value=pos;
    // double cosine_output = vel*cos_sc;

    // iterate to next sample
    double newpos = pos*mul1 + vel*mul2;
    vel -= (pos+newpos);
    pos = newpos;

Ta-da! If anybody wants to go and do some fancy pants math to show why this works, too, I'd love to hear it... :)



3 Comments


February 14, 2008
to my love, OS X.

JUST KIDDING. Quite the opposite in fact. It's been really exhausting porting stuff to OS X. Here are some reasons why:

1) Poor (and often hard to find) documentation-- Yes, some of the newer APIs are decently documented, but dig in and try to use ATSU to render text, and it's a world of pain. Looking through header files that all seem to assume you know what to do. This is tolerable, though, with enough digging you can find what you want.

2) The AudioUnits SDK-- the API for AudioUnits is defined in a header, but not documented. So to use AU, you'd have to either just use the SDK (with EXTENSIVE amounts of code), or reverse engineer it to figure out what calls you need to do to control the plug-ins yourself. Someone obviously spent a lot of time defining an extensible plug-in API, why the fuck don't they document it?! I mean, really, just a "first, call this, then, call that, then, when you're ready to process X, do Y." If this info is somewhere, someone please let me know... (see the next point)

3) The previous two points might to be related to the fact that Apple seems to assume that as a Mac developer, I've been developing for macs continuously since 1984, and have religiously read the developer mailing list since whenever it was created. Apple: for the love of god find some way of getting those mailing list posts linked to/from the relevant documentation pages.

4) There are WAY too many ways to accomplish similar things. The classic example which I bitch about a lot is text rendering--last I checked, there is CoreText (apparently awesome, but 10.5 only), CoreGraphics text functions (seem nice, but lots of limitations including non-functioning text measuring), HITheme rendering (which is nice but doesnt give you much for font style selection), AppKit NSString/NSAttributedString drawing (great, but slow), ATSUI (seems to be the best all around but takes a bit to get to the point where you get what's going on). I understand that there are historical reasons for these APIs, but again, this can be fixed with proper documentation (perhaps a page describing all of the APIs and their benefits and drawbacks).

5) Addition of new APIs in new OS versions. I know Apple wants to sell new OS versions, but from a developers standpoint, it's really difficult to properly support multiple versions of OS X. I'd like to use new OS features if available, but fall back to old versions if not. If there's a clean way to do this, I'd love to hear about it -- on Windows we usually just load the appropriate DLLs if available..

6) Performance on OS X for basic graphics drawing seems terrible. Perhaps if you take advantage of the highly OS X specific stuff, you can get around some of this, but as an example I made two native projects, one for OS X and one for Win32, that create a 640x480 window and try to draw at about 30fps. They fill the background black and draw white lines. On Windows basic double buffering is used, on OS X the system buffers the drawing. The OS X version uses Cocoa and CoreGraphics to draw, and the view is opaque.

The source code which you can build is here (VC6/win and Xcode2.4+ for OS X required).

Results: on the same Core2 hardware: OS X: 11% CPU use. WinXP: 1% CPU use. In fairness to OS X, it was drawing pretty antialiased lines, however when I disabled AA on the OS X build, the CPU use went _UP_ to 20%. Go figure. It's not really the line drawing, either--make it draw just one line the numbers dont change much...

February 14, 2008
and Windows...


Well I don't have anything to really bitch about Windows right now, but I'm really disappointed with all of the VC++ builds after VC6. The issues are a plenty, but it makes it hard to upgrade. All dynamic linking uses msvcrt71.dll etc which even MS doesnt distribute anymore, so you end up having to static link. Bleh.

I guess most people don't care about the size of their software, but for us keeping the program size down is also part of keeping the development process fast and efficient. If I have to upload a 30mb installer and everybody has to download one to test...

14 Comments


January 1, 2008
HAPPY NEW YEAR(S)

(this serves as a reply to those who texted me HNY and didn't get a response from me).

The Radiohead NYE special was (predictably?) good. Mmm. My tivo won't erase that for a while.

We migrated to SVN for version control a while back. Definitely liking it, and Tortoise SVN rules. No good free mac SVN clients I've found, though (anybody?). So for now the command line version isn't bad. I can't believed I'd used VSS and/or SourceOffSite for over 8 years. Eep.

I've set up an SVN server for use with audio and REAPER projects, to aide in some collaboration. It's sort of working, although I think most people aren't used to version control.

Someone REALLY needs to make a web site where you can upload projects with media, then other people can make derived versions, and upload them, and you can go through the whole tree of projects etc. Seriously. Either using something like SVN or whatever. Would be awesome to open up that sort of collaboration. I know there are sites out there doing half of this, but I haven't seen it done really well.

Oh and I never posted this link here, our show we played in November:

But now sadly Christophe has fled the country off to a beach somewhere, and we're lonely and drummerless.

What else? Well it'll have to wait til next time.



Recordings:

freeform jam with biderman

5 Comments


November 3, 2007
holy shit the daily show rules

Been watching some old Daily Shows (which I might add is fucking great that they put them ALL online! HOLY CRAP! AWESOME!).

Just watched election night coverage from 2000, and man, Stephen Colbert CALLED IT. Watch this video:

Now I know you could say he was just joking, but holy shit.



2 Comments


October 10, 2007
Radiohead "In Rainbows"

I'm digging it. A lot. Not as huge to me as some past Radiohead albums were, but then again I probably ruined some of the impact for myself seeing them play these songs live a few times first, whereas before I heard Kid A the first time I had never heard any of it. Not that I'm complaining-- seeing Radiohead live is absurdly fantastic...

October 10, 2007
REAPER 2.0 woohoo


After over a month in beta, we finally released 2.0 final. Woohoo. Here's the changelog (condensed but shown here so I can reflect on the lengthh of it):

  • added elastique Pro, Efficient, and SOLOIST as pitch shifter/time stretcher options
  • action: new actions to toggle/clear/set individual lock modes
  • action: actions to set take by index (1-9) active
  • action: "Take/Paste as takes in selected items"
  • action: "render items to new take" (which is like apply fx but without fx)
  • action: action to toggle item "preserve pitch when changing playrate"
  • automation: added option prefs/editing/"Automatically add/arm envelopes when tweaking parameters in write modes"
  • automation: autoadding vol/pan/playspeed envelopes autoresets trims to unity
  • automation: mute envelopes for tracks/sends (no UI integration for automation recording yet)
  • automation: fixed vol/pan/playspeed tooltips when in automation modes
  • compatibility: perf meter: fixed incorrect ram usage on w2k
  • compatibility: fixed a win2k text drawing gdi corruption issue
  • compatibility: fixed a win2k media explorer refreshing bug
  • compatibility: vertical zooming now flickery in WINE (since WINEs WM_SETREDRAW breaks things -- WINE developers, contact us)
  • defaults: made Take Lane viewing on by default
  • display: fixed bug with changing screen resolutions
  • editing: fixed cutting items in ripple all mode
  • editing: split items at loop selection selects only items in selection (not unsplit previously selected items)
  • editing: apply fx to new take now works on empty items
  • editing: better zoom from scrollbar when zoom set to center on mouse cursor
  • editing: enabled zoom out to see more than a few hours
  • editing: better envelope behavior in item moving and ripple editing
  • editing: fixed bug with slip editing items fudging automation
  • editing: shifting/nudging loop selection works better with time signatures
  • editing: main track view sub-pixel accuracy improvements
  • editing: ctrl+dragging loop selections when item left/right locked now works
  • editing: force selection to beat lengths now supports multiple time signatures
  • editing: new item lock modes (item edges, controls)
  • editing: better drag and drop file positioning in certain instances
  • fx: comment window is now modeless
  • fx: added vertical scrollbar to comment window
  • fx: you can now rename instances of effects to better describe their application
  • fx: action to build multichannel routing for the output of multichannel VSTis
  • fx: action to build 16 channels of midi routing for the current track
  • fx: vsts that have latency and send MIDI now can send ahead of time
  • fx: updated VST samplerate change calls for buggy plug-ins
  • fx: special case code for simulanalog VST plugins (aggressive denormal prevention)
  • fx: fixed alt+drag fx moving bugs
  • fx: fixed plug-in config window close order on quit (good for EmuX)
  • fx: better denormalization prevention methods used throughout
  • fx: faster offlining of plug-ins with large state data
  • fx: startup project loading now initializes audio device before loading plug-ins
  • fx: modifiers when drag and drop adding fx (shift=dont bring up config, ctrl=toggle floating of config)
  • fx: floating fx windows remember their positions when closed
  • fx: less showing of fx chain when "auto-float new fx" is on
  • FX: added JS: utility/bufsave, which lets you route feedback in fx chains easily
  • FX: added JS: utility/time_adjustment which allows delay/predelaying signal
  • FX: added JS: autopeakfilter for fun autowah type effects
  • FX: added some new loser JS fx
  • FX: JS PDC support for effects (pdc_bot_ch, pdc_top_ch, pdc_midi and pdc_delay to specify sample delay)
  • FX: JS shared memory (gmem[]) is now shared across all JS instances in reaper
  • FX: added JS play_state, play_position, and beat_position variables
  • FX: safer window class registration/unregistration in many Rea* fx
  • FX: reacomp/reaxcomp performance improvements
  • FX: better offscreen window checking for ReaNINJAM
  • FX: ReaTune now uses REAPERs pitch shift algorithms (elastique soloist is great for this)
  • FX: ReaTune added "click reduction" mode for SoundTouch and possibly other modes
  • FX: ReaTune manual mode ruler, mousewheel support
  • FX: ReaTune subdivision mode (to update at higher frequencies with larger window sizes)
  • FX: ReaPitch, new multi voice pitch shifter
  • FX: ReaEQ and ReaXComp now update undo states on add/remove of bands
  • installer: now allows selection of pitch shifters to install
  • keyboard: better handling of keystrokes when mouse captured
  • master track: can now have more than 2 channels
  • master track: can now control source channels/phase/volume/pan/etc of each hardware output independently
  • master track: better RMS metering, lots of RMS display options
  • master track: better pdc with anticipative rendering
  • master track: master fx chain no longer defaults to bypassed
  • master track: made solo/mute click modifiers not affect master mute/solo
  • master track: right click marquee works in master track (for envelopes etc)
  • master track: fixed undo with no master hardware outs sometimes adding in a default output
  • media explorer: added "Insert as takes in selected items"
  • media item properties: "choose new file" automatically updates take names
  • meters: better event light for record output (midi) mode
  • meters: updated track metering rounding to better pass synthetic tests
  • meters: better track meter clip indicator hit testing
  • meters: better metering for record output (midi) mode
  • metronome: better metronome countin for tempo changes
  • midi: MID file import can now import tempo maps
  • midi: better looking and faster midi peak drawing
  • midi: midi items are now treated as ticks/Quarter Note, except for items in old projects (which are still ticks/beat)
  • midi: fixed open copy of items sometimes dropping notes
  • midi: better sorting of noteoffs and allnoteoff messages
  • midi: reduced excess sending off allnoteoff loop markers
  • midi: fixed splitting items on notes producing 0 length notes
  • midi: fixed bug in fadein for midi items
  • midi: fixed extraneous notes at end of some items
  • midi editor: can now reflect project time signature changes
  • midi editor: grid/quantize are now fractions of whole notes, not of beats
  • midi editor: separate colortheme settings in prefs (including for piano keys etc)
  • midi editor: fixed bugs with play cursor and looped midi items
  • midi editor: better vertical scrollbar
  • midi editor: better focusing when opening/activating and switching modes
  • midi editor: internal cleanups, improved ctrl+select behavior
  • midi editor: pass through to main window keyboard action
  • midi editor: updates to list editor play cursor, better list editor sorting
  • midi editor: list editor note properties sets focus depending on which column the mouse was on
  • midi editor: better focusing when opening/activating and switching modes
  • midi editor: moving notes now uses both absolute and relative snapping
  • mixer: optional FX and Send views (configurable via the mixer menu)
  • mixer: more settings are now stored in the project
  • mixer: options are now assignable actions
  • mixer: new FX/send views are themeable (mcp_fxlist_norm/byp/off/empty, mcp_master_fxlist_ too)
  • mixer: (theme images): mcp_sendlist_knob.png, mcp_sendlist_meter.png, mcp_*list_arrows.png
  • mixer: fixed incorrect minimum height on nonstandard display DPIs
  • Monkeys Audio: fix for Unicode files, fixes for offline support
  • Monkeys Audio: fixed mem leak, fixed 24 bit stereo mode, optimizations
  • Monkeys Audio: now uses asynchronous disk reads if set
  • option: options to not show peaks for muted tracks/items, or non-selected tracks
  • option: added working set configuration in prefs/general/advanced
  • performance: portions of REAPER are now compiled with the Intel C++ compiler
  • performance: faster zoomed-in peaks display
  • performance: fixed muted folder tracks still running fx
  • performance: updated on-stop behavior to keep audio thread locked for less time
  • performance: UAD synchronous fx multiprocessing support
  • performance: improved anticipative fx processing on looped playback
  • performance: renamed fx renderahead "anticipative FX processing"
  • performance: added new "Synchronous multiprocessing" option, which allows multiprocessing on input monitoring, better UAD multiprocessing, etc
  • performance: per-item pitch shifters are now freed when they are no longer needed or media set offline
  • performance: fixed silence-at-end-of-rendering issue with asynchronous writes enabled
  • performance: more robust asynchronous disk writes
  • performance: fixed SMP rendering glitches
  • performance: fixed cpu munch when stopping at end of project
  • performance: mono items pitch shifted are now processed in mono (big speedup)
  • performance: reduced cpu use of empty tracks
  • perf meter: graph shows cur/avg, range, action to reset graph
  • project directory cleanup: now defaults to sending items to recycle bin rather than deleting
  • reamote: possible fix for Nebula plugins
  • reamote: fixed crash when invalid data received on certain message types
  • reamote: fixed support for larger config packets
  • routing: fixed labelling on hardware outs after adding routing
  • routing: renamed send type "Post-FX" to "Post-FX (V1 deprecated)", added a new, better "Post-FX" mode
  • routing: fixed i/o windows open when adjusting/removing routing bugs
  • routing: better rearoute labelling all around when audio device closed
  • screensets: added keyboard shortcut column and button to edit shortcuts
  • screensets: autosave wont save anymore when switching to same screenset
  • screensets: added auto saving option
  • screensets: fixed docker issues
  • screensets: added mixer flags saving
  • screensets: added last focused window state saving
  • tempo map: overhaul: simple tempo changes no longer force a new measure
  • tempo map: improved tempo editing behavior when editing tempo changes and time sig changes
  • tempo map: lengths calculated across timesig markers now use the time signature at the start to determine measure length
  • tempo map: more accurate tempo envelope saving/restoring
  • tempo map: small fades are no longer adjusted by tempo changes
  • theming: faster drawing, faster mouseover updating
  • theming: background for faders, window backgrounds, name backgrounds, etc support pink line for unstretch areas
  • theming: docker is now independently colorthemeable
  • theming: new default colortheme (by WhiteTie!)
  • theming: support for when path to theme dir changes on diff systems
  • theming: advanced faders can have zero line set
  • theming: configurable fonts for track panels / volpan labels etc
  • theming: track_fxempty_h and track_fxempty_v
  • theming: window drawing improvements (less screen corruption issues)
  • theming: fixed stopped resize of transport drawing issues
  • theming: fixed some playspeed automation refresh issues
  • theming: fixed some dark custom color issues with advanced themes
  • theming: better background image edge scaling when compressed to small spaces
  • theming: classic theme color tweaks (for mcp send/fx list)
  • theming: bg tinting for track labels in advanced themes
  • ui: most modal dialog boxes now restore window focus on close
  • ui: added option for gap between items on adjacent tracks (defaults to 4px)
  • ui: fixed non-fancy peaks display on muted items/inactive takes
  • ui: better envelope spacing (small gap between envelopes)
  • ui: better item loop indicator drawing
  • ui: fixed edge loop indicators on some items
  • ui: fixed zero line drawing issue on items
  • ui: fixed peaks display at end of heavily looped items at certain zoom levels
  • ui: better record mode display for midi overdub modes
  • ui: fader ctrl+precision modes hide mouse cursor
  • ui: better spacing for transport status state
  • ui: better volume fader ganging at extremes
  • ui: grid/snap boxes will now correctly display smaller fractions
  • fixed some tiny PCM-floating point import/export precision issues
  • better external midi editor support (fixes, open copy in external editor creates .mid file)
  • faster dB unit conversion throughout
  • demo song: updated mix
  • new about screen



6 Comments


April 8, 2007
awesome (IFF).. part 2

I'm doing a little guest hosting spot at GearSlutz for the next couple weeks..

Comment...


February 12, 2007
Mmmmmmmmmmmm

Two tasty things:

this little mention of REAPER was nice to read.

And, also, I just got a dual quad core xeon machine.. 8 2.33ghz cores. Wow. Insanely powerful. Quieter than I expected, too. Mmmm. Thank you, Dell (can I have my next one for free for that plug?).

REAPER hauls complete ass on this box. Amazingly fast, and it can use nearly all of the processing power available. I did some testing on my Athlon64x2, and it could do like 12 tracks of FX (reagate+reacomp+reafir+reaverb), and this thing can do over 50. Having flawless audio playback with 8 cores humming away at 95% of each used is a beautiful beautiful thing. Here's a screenshot.

Now when you can get one of these for $1500, then it will be insane. I'm guessing late 2008.

13 Comments


December 15, 2006
porting frustration

(9/10 on the boring scale)

So I just spent the last day or two (I honestly can't remember) getting Jesusonic to run on OS X/x86. I already had it running on OS X/PPC, so I figured it would be easy. Wrooong...

Jesusonic works by compiling code on the fly into native assembly. It actually does this by glueing together stubs of functions (the most critical which are written in assembly for each platform) into code that it can execute. Overall the code it generates is not terribly optimized, but it's definitely not slow either.

So this is what I found in porting JS.

1) the compiler bitched about my assembly code trashing EBX. Turns out, EBX is used for position independent code (PIC) addressing. So I figured I should probably not be messing with EBX, and that the OS needed it. With a bit of additional work on the compile side I got it to not use EBX, but in the end it turned out that EBX only really needs to be preserved within functions that use it, and for my uses I really could use it. Oh well. Time wasted, but hey kinda useful. Stuff still wasnt working right.

2) Many of the assembly stubs for particular functions needed to call C code, whether it be a C library function like pow(), or some of our own code (FFTs, file reading, accessing memory, etc). Since GCC was generating my functions as PIC, the extended assembly syntax failed to assemble (ending up with assembly like "movl ((symbolname-$LABELBLAHBLAH(%ebx))), %edi", etc. So turns out MY compile step needs to actually go generate absolute addresses at runtime, instead of at compile time. Fair enough, that took an hour or so, and a bunch of testing/fixing to make sure that nothing broke.

3) And this was the big bitch, and it took me a long time to figure out. Turns out, and this is well documented, you have to keep the stack aligned to 16 bytes. I would call pow(), and it would end up trying to do an sse load/store at an unaligned address, and things would proceed to blow up. So I had to go update all of my stubs and functions to keep the stack nicely aligned, which is probably not a bad idea anyway. Once I finally got them all correct, I tried it out, and... IT still didn't work. So I ended up spending a lot of time with GDB (Xcode's debugger won't let me see registers, argh), and figured out that, indeed, the stack was aligned when I called my generated, code, but no, the stack wasn't aligned when it got to pow().

After changing some build settings, I found that with -O0, it did in fact work. So then I did some gcc -S -O0 file.c and gcc -S -O2 file.c and compared the generated code for the assembly stubs, and it seems that with -O2, gcc itself would let the stack get unaligned , as long as my stub wasn't obviously calling another function.

I looked for a long time to see if I could disable this in gcc, and I gave up, so on OS X/x86 Jesusonic will have this code for each stub:

pushl %ebp
movl %esp, %ebp
andl $-16, %esp

(run code)

leave

that way, whenever I call out, I can ensure that the stack is aligned, no matter what kind of crap GCC is generating for the function.

The better way of dealing with this would probably be to write these functions in assembly directly, or improve the code that cuts up the stubs to have it filter out the stack frame setup that GCC produces anyway, but hell I'm too lazy and this works and it's reasonably fast enough as it is. And most importantly, I get to get back to the fast, satisfying building of UI and porting of easy things.



4 Comments


December 9, 2006
mac porting...

In August I began cleaning up REAPER's source code, and began separating the platform-specific code (mostly UI) from the mostly-portable code. Ten days ago, after 3 months of doing that while also adding new features and releasing new Windows versions every few days, I began spending a great deal of time actually writing a bunch of Cocoa code so that we could have it run on OS X.

It has gone very well, expect some preview version around Christmas.

I love it when this stuff goes faster than I had expected. I'm going to detail some of my experiences here.

There's a lot to like about programming on OS X, but there's also plenty of idiocy.

CAUTION-Boring programming discussion follows. These are mostly things that I have sort of, but not completely correctly, working.

For example, if you wish to draw text, there are countless ways to do it, and at least for what I wanted to do (emulate DrawText for our GDI emulation layer), I still haven't found a way that works as I want. The first way I tried was using CGContextShowText, which worked, except the only way I could find to measure the text before, or after drawing it didn't seem to work (using CGContextSetTextDrawingMode with kCGTextClip to modify the clip path, then get the bounding rectangle of that). So without any way to measure the rendered text, I had to find another way. I could use NSAttributedString to draw, but the first problem is that I wanted to supprot drawing to an arbitrary CGContext, which may or may not be the "active" context. Then, suggested to me, was to use Carbon's HIThemeDrawTextBox etc, which isn't really documented at all (other than in the header file and some examples). HIThemeDrawTextBox works, except the font I selected using CGContextSelectFont isn't used. It appears I could use some other API to set the font, but I havent spent that much time on that. Why can't there just a be a simple, working way?! At least win32's DrawText just works (though I hear the internals are a nightmare).

OK I won't go too much more into those sort of things. The good things are some things are just easier. Anytime you want to modify the behavior of something, it's WAY easier, since you can do a simple objective C subclass, rather than having to do the tricky hacks we do in Windows. Porting the customizable keyboard code to OS X took an hour or so. Getting it to work originally on Windows took many times that.

Rendering with Quartz just looks nice, too. The plain Windows GDI calls just look harsh and cruddy in comparison.

Here's an interesting challenge: on Windows, REAPER renders its play cursor (the line that moves constantly with playback) by using XOR drawing. It renders it by flipping all of the bits in the line, then when it needs to erase the cursor (in order to draw it in the new position), it can just XOR again. Win32 makes this available by using DrawFocusRect(). Anyway, on OS X this isn't possible, to my knowledge, because the system handles so much of the drawing process. I didn't want to be responsible for updating any of our track view at 30fps+, so I had to come up with another solution. After some experimentation, I found that you could create a new NSWindow, make it a child of the main window, and move it around as the play cursor. And it works, the system handles redrawing the track view, from its cached rendered version, so it's FAST, probably hardware accelerated, and you can do neat things with the alpha channel of the cursor. The verdict: while you can't do oldschool things like XOR drawing, you can do things sexier.

So to aid porting, I've created a new part of WDL (our general reusable code library, pronounced "whittle"), called SWELL (Small Windows Emulation Layer Library or something). So far it emulates (at an API level), portions of the Windows GDI, menu API, MessageBox, ini file (GetPrivateProfileString etc), and a bit more. Eventually we'll probably BSD license SWELL, too.

One interesting thing in SWELL is a set of macros and small functions that let us paste in menu definitions from a .rc into a C++ source file and have it generate a HMENU for it. Fun use of the C preprocessor, if you ask me.

Anyway, this is all challenging, and as a result, mostly fun.

December 9, 2006
programming style and process


I previously said I was planning on writing an article on coding style etc, and while I haven't gotten around to finishing it, I'll go ahead and discuss some of it.

1) If you program, and you're working on something that you expect to be working on for more than a couple hours, use version control. The benefits are countless. Safety, yes, but also, it gives you the ability to easily see everything you've done (if you're religious about checking your code in often), and even more importantly (to me), it lets you diff and review your changes before checking in. I do this all of the time, to make sure everything I did was everything I wanted, and that I didnt fuck anything up.

2) Don't be afraid to let things get messy. A very common (and valid) sentiment in programming is to avoid "premature optimization", where the programmer spends too much time too early on some part which may or may not even need it, introducing complexity for the sake of possible speed improvements etc. I don't hear people say this much, but I think you should take the same stance on organization. If you're programming software, and you need to add some new function for some task, don't be afraid to just toss it in near where you need it, and see what happens. Don't go creating tons of new files every time you need them. Moving code around for organization later is easy, and if you don't do it too soon, you'll a) stay focused, and b) save time in the event that the code you added wasn't used. Which brings us to the next point:

3) Don't be afraid to toss out code that you've written. Sometimes you have some problem and code a solution for it, and at the end of it, you just don't like it. If you don't like it, and think you could do it better the second time, do it the second time.

4) Going back to point #2, don't obsess from the beginning about reusability. Write code that you need, and once you're using it and see how you actually need to reuse it, then go make it reusable.

5) Finally, evolve your code. Getting something to the point of limping is the hardest part, so you should try to get to it as fast as possible. Once you're there, progress is much faster. It's like waiting for a minute to pass. If you look at a clock with a seconds hand, it goes quick, but if you just stare into space, it takes forever. Get to the point where you can see progress, then enjoy it (and test your work often).

More later, perhaps...

December 9, 2006
oh, and


I added a super simple thing to prevent spam on these comments, and it has worked perfectly. We'll see how long that lasts...



12 Comments


[ older results... ]



Search comments - Ignore HTML tags
search : rss : recent comments : Copyright © 2024 Justin Frankel