Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
For me swapAt worked fine when i replaced it in your source code, using Swift 3.2 though.

Ok thanks for clearing that up, wasn't sure if it's finished because of the screenshot you posted.

There is absolutely nothing wrong with my swap code, and I'll tell you why. In the future, please try to understand the context around my code before claiming it is wrong :)

That piece of code does not even need to be synchronized, and that is why I didn't bother doing so.

Tracks are only swapped when being reordered (moved up or down within playlist). And the algorithm for moving tracks up/down, is, by necessity, a serial operation. When a swap is ongoing, the code can be confident that no other array modification is occurring. In fact, currently there are no concurrent array modification operations ... and this is the intended design, thus far.

Code:
// Pseudocode (not Swift code)
func moveTracksUp(tracks) {

// Assume tracks sorted in ascending order by index

for track in tracks {
     swapWithTrackAbove(track)
}

}

// Serial, not concurrent
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
A bit of a UI refresh, partly necessitated by the new feature (group views). Just a heads up of what's coming ...

NOTE - The code is not stable yet. It desperately needs cleaning up and a lot of testing.

EQ.png


OnOff.png


Playlist.png
 
Last edited:
Finally got rounded corners on the windows. I kinda hacked it with a rounded container box and window transparency. Also, separated the playlist summary into 2 parts.

SummaryFixed.png
 
Last edited:
I've added some new features, and refined the UI.

Some of these new features are still being tested.

SummaryFixed.png


OnOff.png
 

Attachments

  • Playlist.png
    Playlist.png
    120.5 KB · Views: 106
Last edited:
Have tried the experimental version and everything seems to work like it should for me. At least all the basic UI interaction, like adding/removing songs, sort, find, reorder, toggles.

Only thing I noticed is that 'shuffle' automatically deselects when 'repeat one' is selected and the other way around when 'repeat one' is active and shuffle gets selected. This probably is intended, but i think it's not how it should be.

Well and CPU usage isn't the best with those animated playback indicators, but that's already a known issue.

So, you sure did a great job with those new features. Also your redesign improved the overall looks (red accent color looks nice). Not sure if i like the redesigned icons tho. They're kind of too square and not sure if that goes well with the overall rounded corners elsewhere. Also i really liked the old on/off switch in the effect panel compared to the new one, but that's just taste.

Regarding rounded corners I also did some experimentation on that as well. It's obvious that with hidden titlebar the rounded corners also get removed. But so do the resize indicators. The weird stuff started when I removed the titlebar via code instead of IB. The resize indicators were still there, but the resizing was broken and only worked visually. So the view got bigger, while the window didn't and you would click through the window unable to select it.

in the end my approach was to just make it transparent and full-size-content, so i can still have the rounded corners and I can keep the indicators. On the other hand a borderless window behaves differently when moved off-screen. For example you can't move the titlebar of a titled window out of screen on the bottom, which might be unwanted behavior, especially when toggling the effects would make the playlist go off screen. Not sure which approach is the better one.

Instead of adding a rounded container box, giving the window's content view a corner radius would have also been possible, but since it works fine with the rounded box there's probably no need to change it.

Last but not least further development stalled on my side for now (probably for a few weeks). After all you made it clear to me that there's so much more stuff i need to understand before working on a project like this. So I started educating myself more about concurrent programming, GCD, threads and queues and a lot of other stuff. Guess it'll be a long way before I can call myself a decent programmer... but that's a good thing :D
 
  • Like
Reactions: 0002378
Have tried the experimental version and everything seems to work like it should for me. At least all the basic UI interaction, like adding/removing songs, sort, find, reorder, toggles.

Only thing I noticed is that 'shuffle' automatically deselects when 'repeat one' is selected and the other way around when 'repeat one' is active and shuffle gets selected. This probably is intended, but i think it's not how it should be.

Well and CPU usage isn't the best with those animated playback indicators, but that's already a known issue.

So, you sure did a great job with those new features. Also your redesign improved the overall looks (red accent color looks nice). Not sure if i like the redesigned icons tho. They're kind of too square and not sure if that goes well with the overall rounded corners elsewhere. Also i really liked the old on/off switch in the effect panel compared to the new one, but that's just taste.

Regarding rounded corners I also did some experimentation on that as well. It's obvious that with hidden titlebar the rounded corners also get removed. But so do the resize indicators. The weird stuff started when I removed the titlebar via code instead of IB. The resize indicators were still there, but the resizing was broken and only worked visually. So the view got bigger, while the window didn't and you would click through the window unable to select it.

in the end my approach was to just make it transparent and full-size-content, so i can still have the rounded corners and I can keep the indicators. On the other hand a borderless window behaves differently when moved off-screen. For example you can't move the titlebar of a titled window out of screen on the bottom, which might be unwanted behavior, especially when toggling the effects would make the playlist go off screen. Not sure which approach is the better one.

Instead of adding a rounded container box, giving the window's content view a corner radius would have also been possible, but since it works fine with the rounded box there's probably no need to change it.

Last but not least further development stalled on my side for now (probably for a few weeks). After all you made it clear to me that there's so much more stuff i need to understand before working on a project like this. So I started educating myself more about concurrent programming, GCD, threads and queues and a lot of other stuff. Guess it'll be a long way before I can call myself a decent programmer... but that's a good thing :D

Thanks so much for the detailed feedback. I will address the issues you've brought up a bit later, but for now, thanks for trying it out and getting back to me !

BTW, I didn't mean to discourage you from working on this project or any project. I would have said the same thing to anyone who claimed a piece of my code was wrong/buggy, even if he/she was twice as experienced/professional as me. I think you're outstandingly sharp given that you're just beginning programming. You are definitely more than qualified to work on this project (which is actually quite simple compared to some others out there). I just meant that, if someone is going to say something doesn't work, with confidence, the due diligence should be performed beforehand. That's all.

And, you have given me some great feedback and things to think about, regarding this project. I greatly appreciate it !
 
  • Like
Reactions: Tobias_Dunkel
Well, I have to thank you as well. After all you haven't discouraged me by any means, rather motivated.

One thing I noticed is the performance drop with TableViews in general when they get bigger. Like there is serious stuttering while scrolling when the playlist occupies half the screen. But at the same time when you take a look at Xcode's instruments analysis tools with an even more complex table view, it's super smooth no matter the size. So I wonder how Apple does it. Like, do they have their own implementation of a TableView class? Or are they just using cell based TableView with a custom NSCell class?

Would be nice to find a way to make bigger table views more smooth.
 
  • Like
Reactions: 0002378
Well, I have to thank you as well. After all you haven't discouraged me by any means, rather motivated.

One thing I noticed is the performance drop with TableViews in general when they get bigger. Like there is serious stuttering while scrolling when the playlist occupies half the screen. But at the same time when you take a look at Xcode's instruments analysis tools with an even more complex table view, it's super smooth no matter the size. So I wonder how Apple does it. Like, do they have their own implementation of a TableView class? Or are they just using cell based TableView with a custom NSCell class?

Would be nice to find a way to make bigger table views more smooth.

Yes, I have noticed the stuttering as well. And not only have I've given it some thought, but have also attempted solutions, with no luck at all.

I think that Apple may be doing some sort of caching of table cells that have not changed over time. In other words, they may have a cell cache that they smartly invalidate and update as the data contained in cells changes, as opposed to creating the same cell over and over again every time the cell is rendered. I tried to cache table cells, but saw some weird results. In the end, I decided that it's more important to show correct data and be slow than to show the wrong data and be super smooth.

That is just one theory, of course. I don't know if the creation of table cells every time viewFor(row, column) is called is really the problem. It may be.

The main problem is ... I don't have a very good understanding of the internals of NSTableView/NSOutlineView, and I have not dug very deep into it. But, this is definitely something that would be good to improve on, as far as performance of the app goes. It could be a great research project for you ! I may also look into it someday.

Good observation !
[doublepost=1509674552][/doublepost]
Only thing I noticed is that 'shuffle' automatically deselects when 'repeat one' is selected and the other way around when 'repeat one' is active and shuffle gets selected. This probably is intended, but i think it's not how it should be.

Yes, good observation, and I'm glad you brought it up because I would like to get a second opinion on this issue. This is the intended behavior ("repeat one" and "shuffle on" are mutually exclusive and cannot both be selected at the same time), and the logic behind it is: if I'm repeating a single track, then shuffling is irrelevant. Likewise, when I'm shuffling tracks, I need to have more than one track in my queue to shuffle. I have noticed that other apps do it differently. But, to me, it would be confusing to have both on simultaneously. As a user, when I select repeat one, and then later change my mind and want to shuffle my tracks, I want the previously selected "repeat one" mode to turn off, so that it is clear what I'm doing now.

If I'm not mistaken, the two modes are, in fact, mutually exclusive, right ? What do you think ?

Now, there is obviously at least one other way to do it - I could allow both to remain selected simultaneously and just have the sequencer logic do one of the following:
1 - Choose whichever of the two was selected most recently (this would make for ugly code).
2 - Have one of the two take precedence over the other (for instance, if shuffle is selected, always ignore repeat one).

In my opinion, the above alternative solution introduces ambiguity to the user experience.

Well and CPU usage isn't the best with those animated playback indicators, but that's already a known issue.

Again, I partially agree with you. But, I want to give you a perspective that probably no other programmer will agree with (most would agree with you).

Q. Why do our computers have CPUs ? What is their purpose ?
A. To do work that we deem useful.

Ok, next question ...

Q. If an app that plays music and shows funky animations is considered, by the user, to be "useful", then what is wrong with using up 20% of CPU ? What are we "saving" that CPU time for ? To brag, "Look, my app only uses up 5% of CPU while yours uses up 20%" ? What is the ultimate goal here ?

A. Hmm ... good question. I want to save CPU time for other more CPU-intensive tasks like photo/video editing ? Also, less CPU means less energy usage ?

Ok, yes, our computers need to multi-task, and a lot of time, we run the music app in the background, so I can't even see the funky animations, so running them is a waste of resources. Makes sense. Great ! Make it easily configurable with a button, so that when I'm playing with the app (in the foreground), I can see it, but when it's in the background, it is not wasting resources !

Final question ...

Q. Given that all MacOS computers (these days) have at least 2 cores, and many have 4 (potentially more if we're talking desktop), is 20% of one processing core too much to expend on an app that I consider useful ?
A. Hmm, now that I think about it, ... not really. If I'm on a top-end iMac or iMac Pro, that extra CPU usage is negligible.

Final verdict ...

Let's make it configurable, so that users who're running 100 Chrome browser tabs on on their Macbooks have some CPU to spare, while the Hollywood graphic designer on his Mac Pro can see the animation if he chooses to give a small part of one of his 32 cores to Aural player :)

So, you sure did a great job with those new features. Also your redesign improved the overall looks (red accent color looks nice). Not sure if i like the redesigned icons tho. They're kind of too square and not sure if that goes well with the overall rounded corners elsewhere. Also i really liked the old on/off switch in the effect panel compared to the new one, but that's just taste.

Thanks. Ok, by square icons, are you referring to the playlist window controls ? Dock and Maximize ? I don't like the maximize controls either, to tell you the truth, but I couldn't find better ones that are clearly visible to the user. I spent hours looking for better icons.

Interesting that you liked the old on/off switch ! I thought they looked medieval, or like Albert Einstein might have appreciated them, but I just never found the time/motivation to change them out :D Yes, it's a matter of taste, and I prefer the newer icons :)

Regarding rounded corners I also did some experimentation on that as well. It's obvious that with hidden titlebar the rounded corners also get removed. But so do the resize indicators. The weird stuff started when I removed the titlebar via code instead of IB. The resize indicators were still there, but the resizing was broken and only worked visually. So the view got bigger, while the window didn't and you would click through the window unable to select it.

in the end my approach was to just make it transparent and full-size-content, so i can still have the rounded corners and I can keep the indicators. On the other hand a borderless window behaves differently when moved off-screen. For example you can't move the titlebar of a titled window out of screen on the bottom, which might be unwanted behavior, especially when toggling the effects would make the playlist go off screen. Not sure which approach is the better one.

Instead of adding a rounded container box, giving the window's content view a corner radius would have also been possible, but since it works fine with the rounded box there's probably no need to change it.

BTW, this is very important - the way that key press events are sent to windows that have titles is very different from how they're sent to title-less windows. Make sure that, if you add a title bar, the UX does not change. I can guarantee you it will be weird. The playlist window will lose focus when you click on the main window (play button for instance), and I noticed other weird behavior. I didn't like it at all !

I like the playlist to be and look in focus, 100% of the time. That only happens when there are no title bars. And, all the key events are sent in a predictable and consistent manner. Add a titlebar and it gets totally ****ed.

I'm not claiming that I know more about windowing than you do ... you've clearly spent some time on it and probably know more than me. I'm just saying this from the perspective of someone who has experimented with different solutions and also from a UX perspective. To me, consistent key event behavior and playlist focus are top priorities. If focus shifts back and forth, it doesn't look like the 2 windows are part of one app. The whole experience is seamless (and much better) when the app responds to events predictably no matter which window you are interacting with.

Last but not least further development stalled on my side for now (probably for a few weeks). After all you made it clear to me that there's so much more stuff i need to understand before working on a project like this. So I started educating myself more about concurrent programming, GCD, threads and queues and a lot of other stuff. Guess it'll be a long way before I can call myself a decent programmer... but that's a good thing :D

Again, don't let my comment dissuade you. If I sounded arrogant or condescending, I apologize. I just didn't like being told, "Hey, this doesn't work. You need to do it differently." (when, in fact, it does work). If there was a genuine problem with the code, I would have happily acknowledged it as well.

I'm also learning Swift programming and the MacOS ways of doing things, which are very different from the Core Java back-end world that I'm more used to.

Glad to have you on board this project ! Thanks again for the feedback !
 
Last edited:

It's become real nice in terms of snapping - I only just noticed the small buttons to have a longer horizontal player or regular vertical player. I ran into some issues where the snapping would come un-snapped when I resized the playlist; it broke the feeling of the together-ness of the player. It's a real non issue and just me dragging and clicking like I have fat fingers.

Would you mind if I send off a link in a Private Message to a export of a .sketch file (as png) file that I've made with how I envision the Aural player? I need to edit it just a little now that Aural has been spiffied up. I still couldn't figure out Xcode to the point that I could drag in graphics and actually see the player change form. Thus, I only have some graphics.
 
  • Like
Reactions: 0002378
It's become real nice in terms of snapping - I only just noticed the small buttons to have a longer horizontal player or regular vertical player. I ran into some issues where the snapping would come un-snapped when I resized the playlist; it broke the feeling of the together-ness of the player. It's a real non issue and just me dragging and clicking like I have fat fingers.

Would you mind if I send off a link in a Private Message to a export of a .sketch file (as png) file that I've made with how I envision the Aural player? I need to edit it just a little now that Aural has been spiffied up. I still couldn't figure out Xcode to the point that I could drag in graphics and actually see the player change form. Thus, I only have some graphics.

Thanks for the feedback. Yes, the playlist will un-snap if you accidentally move it even one pixel away from the contact edge it shares with the main window. In other words, let's say it is snapped to the right of the main window. So, if you move the playlist even one pixel left or right, it is no longer considered "snapped". This is intended behavior. It's as if the app thinks you are trying to detach it from the main window. This is to allow the user to detach the playlist when desired. Unfortunately, as you discovered, the resizing needs to be done carefully, because if it results in a move, unsnapping will occur.

Yes, absolutely, feel free to send me any mockups or sketches or other ideas you may have. I will admit that I am not a UI expert. I've been a back-end programmer pretty much all my career, so my imagination when it comes to UI is limited.

Thanks !
 
Okay, didn't know until now that the key presses are handled different between titled and borderless window. After all the whole two window thing is a bit complicated. What would be your opinion on a single split screen window? In my opinion it would be an interesting concept. Since all transparent parts of a borderless window are click-through you can still make it look like two separate windows and change the docking programmatically by reordering the split view items and switching the split view between vertical/horizontal.

Attached a quick mockup how it could look. This way maybe a lot of complicated logic can be removed from the code and handling a single window is easier after all. You can even make it fullscreen and have the player and the playlist fit perfectly on screen. Only downside would be that you can't independently move the playlist anymore. But this could also be something positive since both windows cannot overlap anymore.

Edit: reuploaded with more test buttons
 

Attachments

  • customWindowTest.zip
    62.7 KB · Views: 347
Last edited:
  • Like
Reactions: 0002378
Thanks for the feedback. Yes, the playlist will un-snap if you accidentally move it even one pixel away from the contact edge it shares with the main window. In other words, let's say it is snapped to the right of the main window. So, if you move the playlist even one pixel left or right, it is no longer considered "snapped". This is intended behavior. It's as if the app thinks you are trying to detach it from the main window. This is to allow the user to detach the playlist when desired. Unfortunately, as you discovered, the resizing needs to be done carefully, because if it results in a move, unsnapping will occur.

Yes, absolutely, feel free to send me any mockups or sketches or other ideas you may have. I will admit that I am not a UI expert. I've been a back-end programmer pretty much all my career, so my imagination when it comes to UI is limited.

Thanks !

Great. I get it more now than earlier :) It's great interacting with a developer.

I've made an Aural icon that you can use or suggest changes to if you feel like it doesn't capture anything Aural-wise here:

https://1drv.ms/u/s!AjS7xphB5gYl7H095n4sA5L7gliw

Aural-Dock icon-screenshot.png
 
Found this project on github: (may help with reducing the CPU usage on the animations)
https://github.com/wangjwchn/AImage

If someone wants to safrifice performance to make something look better and make it more enjoyable, then thats totally fine. Still, a music player is often running in the background and does it for a longer period of time. The option to only load the animations while the window is visible/open would be a good compromise and if it can be done without a huge amount of work I am totally in for it. After all animations are great and would make the player feel more alive. But if it's not possible without great effort, then I agree with you on an option to enable/disable animations in the preferences.
 
  • Like
Reactions: 0002378
Found this project on github: (may help with reducing the CPU usage on the animations)
https://github.com/wangjwchn/AImage

If someone wants to safrifice performance to make something look better and make it more enjoyable, then thats totally fine. Still, a music player is often running in the background and does it for a longer period of time. The option to only load the animations while the window is visible/open would be a good compromise and if it can be done without a huge amount of work I am totally in for it. After all animations are great and would make the player feel more alive. But if it's not possible without great effort, then I agree with you on an option to enable/disable animations in the preferences.

Yes, I think it would be fairly easy to only show the animations while the window is being shown. Look at methods in NSWindowDelegate. There should be some method like windowDidAppear() or something like that, which will allow us to respond and show/hide the GIFs.

Great idea, actually !

There is one more feature that, I think, can be selectively enabled/disabled based on background/foreground "mode". Eager predictive loading of track info, based on tracks that will likely play in the near future (next/previous tracks, for instance). That can also be disabled when the app is in the background and user-interactive-level responsiveness is not that critical.
 
UPDATE - The new features are now available in the main build. I will continue testing and submitting bug fixes as needed.

https://github.com/maculateConception/aural-player/blob/master/Aural.app.zip?raw=true
[doublepost=1509703869][/doublepost]
Found this project on github: (may help with reducing the CPU usage on the animations)
https://github.com/wangjwchn/AImage

Tobias, just for fun, I thought I'd share an image of Aural from the good ol' days of its inception :D

Aural-thenAndNow.png
 
Okay, didn't know until now that the key presses are handled different between titled and borderless window. After all the whole two window thing is a bit complicated. What would be your opinion on a single split screen window? In my opinion it would be an interesting concept. Since all transparent parts of a borderless window are click-through you can still make it look like two separate windows and change the docking programmatically by reordering the split view items and switching the split view between vertical/horizontal.

Attached a quick mockup how it could look. This way maybe a lot of complicated logic can be removed from the code and handling a single window is easier after all. You can even make it fullscreen and have the player and the playlist fit perfectly on screen. Only downside would be that you can't independently move the playlist anymore. But this could also be something positive since both windows cannot overlap anymore.

Edit: reuploaded with more test buttons

Hey, I tried building your project and wasn't able to. Which Swift version did you use ? The deployment target looks to be High Sierra.

I'm on XCode v8.3 on Sierra. Will I be able to build it ?

(I know I can figure this out on my own, but it's faster if you just tell me.)
 
Hey, I tried building your project and wasn't able to. Which Swift version did you use ? The deployment target looks to be High Sierra.

I'm on XCode v8.3 on Sierra. Will I be able to build it ?

(I know I can figure this out on my own, but it's faster if you just tell me.)

Since im using Xcode 9.1 target is High Sierra by default. Forgot to change it. I made an updated version of the UI exploration which I just finished. This time with complete left/right/bottom docking functionality. Reduced target to 10.11 so you should be able to open it.

Would be nice if you could try it out and tell me what you think about it in terms of UX compared to two separate windows. The whole code for getting all this behavior is also very minimal.

Since with 3.5 MB the file is too big to upload it on the forum, here's a dropbox link to the built version.

https://www.dropbox.com/s/yc9r40l4wrkbo0p/MusicUIExploration.app.zip?dl=0
 
Since im using Xcode 9.1 target is High Sierra by default. Forgot to change it. I made an updated version of the UI exploration which I just finished. This time with complete left/right/bottom docking functionality. Reduced target to 10.11 so you should be able to open it.

Would be nice if you could try it out and tell me what you think about it in terms of UX compared to two separate windows. The whole code for getting all this behavior is also very minimal.

Since with 3.5 MB the file is too big to upload it on the forum, here's a dropbox link to the built version.

https://www.dropbox.com/s/yc9r40l4wrkbo0p/MusicUIExploration.app.zip?dl=0

Will try it out soon, I promise.

BTW, as per your brilliant suggestions, I'm doing the following:
- Moving all playlist-related windows (playlist views, search dialog, sort dialog) into their own separate XIB file
- I've figured out how to respond to window/app events signifying that the app is in the background, and I'm disabling the GIFs when that happens. I implemented a quick n dirty solution just to see how well it would work, and it worked effortlessly and beautifully.

You've given me some great suggestions. It's good to have two heads on this project.
 
Did some experimentation on table views to figure out the bad performance we get on the playlist when scrolling. Downloaded some example code from Apple where a table view was used to present a whole lot of data.
In this sample the table view was smooth all the time, even when using it on a fullscreen view. So I played around a bit and tried out some stuff.

I came to the conclusion that the bad performance partly comes from the transparency and the way we achieved it.

The following shows some examples and how it affected the performance in a fullscreen table view.
In all cases the playlist was fully opaque and only had a little gap to the window's borders on each side.
Also the tableview only consisted of text data, so no embedded subviews or other elements in the tables content.

Didn't affect performance a lot:
- making the window or window's content view fully or semi transparent
- adding four effect view bars on the sides to cover the rest of the window besides the playlist (on the other hand doing the same with semi transparent views did affect performance while scrolling)

Affected performance:
- adding a fully or semi transparent view to the content view and spanning it to the content view's bounds (so making it full size) had a big impact on the performance, no matter the Core Animation Layer settings (same with effect view)
- making the content view itself an effect view
- adding lots of auto-layout elements

Enabling 'reduce transparency' in the accessibility settings got rid of all the performance problems when using visual effect views.

Haven't spent so much time on it, so there are many combinations of views and settings I didn't test. Maybe I'll so some more experimentation with avoiding bad performance due to auto-layout. After that I'll try to fix the playlist performance on the Aural player itself.
 
  • Like
Reactions: 0002378
Did some experimentation on table views to figure out the bad performance we get on the playlist when scrolling.

You, Sir, are a genius !

I made all the playlist views opaque (and also the tab group) and selected "Draws Background" for all of them. And it made a huge difference ! Scrolling is buttery smooth with small data sets and quite decent even with 1200 tracks. I had to modify how the cells are colored and the fonts and stuff, but that was trivial. Previously, the playlist had down syndrome; now, it just gets nervous.

I never thought to attack the problem from the angle of UI/rendering, because ... guess what ... I'm a back end Java developer :) I never even thought about things like transparency and how they would affect performance. That's why I was trying to look at things like caching cells in the data source ... which is what a Java server dev would look at.

I've committed the changes and released a new build with the fix. Try it out ! See the fruits of your labor :D

https://github.com/maculateConception/aural-player/blob/master/Aural.dmg?raw=true

This build is dedicated to Tobias Dunkel
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.