I just want to keep the API simple, clean and consistent. Having a good design is much more important than making things work and available.
I agree 100%
Let's look at this another way. From what I see there are 3 things about Music2 that make it weird/inconsistent/incompatible with the existing API:
1) It requires that both intro and loop portions share the same channel count and samplerate.
2) It bypasses the existing loop system and implements its own looping
3) The duration calculation is a little strange.
If all 3 of these points could be addressed, then maybe this would be something easier to implement.
So let's look at possible solutions:
1) Unfortunately, I don't think there is a solution for this. Not unless you build in some kind of resampler which would be more trouble than it's worth. On the plus side, this limitation doesn't really make the API inconsistent, so it's not that big of a deal, imo.
2) The main reason for this is because, as far as I can tell (and I might be wrong as I haven't extensively looked at the code), SoundStream::OnStart() is called to implement the looping in derived types. This is a problem for Music2 because starting and looping will have 2 different results.
The fix for this would be to create a virtual OnLoop() function in SoundStream, and to modify the looping code to call OnLoop instead of OnStart when it needs to restart the loop.
This would require changes to SoundStream which is why I didn't go this route in my original attempt. I was going for an "as few changes as possible" quick-fix. But for a more long term solution I think this is the way to go.
Other derived types wouldn't need to be changed. SoundStream::OnLoop could just call OnStart by default, and only derived types that need different behavior (ie: Music2) would re-implement both.
I think that overall, the changes to make this work would be very minor and wouldn't impact the API or overall design very much. And after the changes are made, the existing looping system will work as expected in Music2.
3) I guess the solution for this depends on what you define the "duration" as. Is it the duration of the portion that loops? Or is it the duration of the whole thing until it starts looping? My code interpretted it as the latter. Although I'm not sure if that's what you had in mind.
If worse comes to worse you could make 2 durations.. like a loop duration and a full duration, and have different functions to return each. But that's getting into messy API changes that probably aren't a good idea.
Just throwing ideas out there. Like I said I'd really like to see this or something like it get implemented in SFML 2.0. I think it'd be a big improvement. Once you have some time to think about it, I'd be very interested in hearing your thoughts.
Thanks for reconsidering!