Project Structure - richardjwild/arctracker GitHub Wiki
I had now reached the point where there was no code left in the project that I felt awful about and had to clean up. The main loop inside play_mod.c was a bit too large for my liking, but I decided to leave it alone for the moment, because I was planning later to add support for PortAudio so that I could move development from the virtual machine to my Macbook. Implementing support for PortAudio would require moving from a blocking audio i/o model, as Arctracker currently uses, to a callback-based model, which would involve pulling the playroutine more or less inside-out. Therefore I didn't see any point refactoring it further, given that it was probably going to undergo radical change anyway. It was clean enough to be getting on with.
For now, I really wanted to change the project structure. All the project files were stored in a single directory, which was bad when Arctracker comprised just four C files, but was seriously untidy now that it comprised a half dozen or so. Also the Makefile had been allowed to get out of date, it did not include all of the header file dependencies. So the first thing I did was refactor the Makefile which also involved improving my skills with make.
Next I moved all the source files into a new src directory, which also involved removing quite a lot of my previous changes to the Makefile. I also arranged for all the object files to be compiled into an objs directory, and the executable to be placed in bin. Now this all was an improvement, but I wanted to go further. The source files were now all kept separate, but I really wanted to split them up into subdirectories to organise them better. Unfortunately I also had to remove the header file dependencies, which was a serious issue that needed to be fixed, because now the build system would not rebuild the project if one of the header files changed.
In the next commit I separated the source code into subdirectories:
src
|-- arctracker.c
|-- arctracker.h
|-- config.h
|-- Makefile
|-- audio
| |-- audio_api.h
| |-- gain.c
| |-- gain.h
| |-- mix.c
| |-- mix.h
| |-- mu_law.h
| |-- period.c
| |-- period.h
| |-- resample.c
| |-- resample.h
| |-- write_audio.c
| +-- write_audio.h
|-- audio_api
| |-- alsa.c
| |-- alsa.h
| |-- oss.c
| +-- oss.h
|-- chrono
| |-- clock.c
| +-- clock.h
|-- formats
| |-- desktop_tracker_module.c
| |-- desktop_tracker_module.h
| |-- tracker_module.c
| +-- tracker_module.h
|-- io
| |-- configuration.c
| |-- configuration.h
| |-- console.c
| |-- console.h
| |-- error.c
| |-- error.h
| |-- read_mod.c
| +-- read_mod.h
|-- memory
| |-- bits.h
| |-- heap.c
| +-- heap.h
+-- playroutine
|-- effects.c
|-- effects.h
|-- play_mod.c
|-- play_mod.h
|-- sequence.c
+-- sequence.h
I struggled mightily with the Makefile trying to write a general rule for compiling object files, that would compile src/audio/gain.c and write objs/gain.o. It always wanted to create objs/audio/gain.o instead. While fiddling, I accidentally discovered that compiling and linking all the source files into the executable in one command was considerably faster than compiling all the object files and linking them separately. I pondered this for a while, and decided I could not think of any advantages to compiling and linking separately in a project this size, so I abandoned the struggle and just went with it. I re-added the header files as dependencies, which was now trivially easy because the single build step now depended on everything.