This is tricky to explain, so rather than explain what was wrong, I'll describe how it works now. Whenever a ScopedTempoMapOwner::in() call occurs, we check the current thread-local tempo map ptr. If it is not owned by us (and we have a local tempo map that we want to use), set it so that it is. We continue to fetch() the global tempo map ptr back into the thread-local ptr when the local scope depth drops to zero.