One way to accomplish your goal is to have set of classes that have just the functionality that should be exposed outside the library. |
An interesting idea, but it is subject to the same problem. Consider that Sound contains an InternalData member, that member would still either need to be public (exposed) or I'm stuck wrestling with the same issues.
To begin with, I wouldn't get hung up on how C++ or any other language approaches object theory [snip] You will then be able to implement your ideas properly in any language. |
Well -- considering I'm writing the lib in C++, and having an issue with my design vs. C++'s friendship system, it seems logical to me to ask this in the context of C++.
> A Mixer is not a Sound. (This is just as ridiculous as a Bicycle having a HeightWeightRatio! ;))
|
My Sound base class provides volume/panning/fading/etc controls. Consider the following scenarios:
- Game wants to mix sound effects seperately from music so that volume levels can be adjusted independently. Easily accomplished by playing sound effects in their own mixer, using that mixer's volume level as a "master" volume for sound effects, then playing that mixer and the BGM in the main mixer for output. Easily accomplished because the Mixer can be played like any other Sound.
- Game wants to play file types of varying samplerates without having to resample each sound prior to mixing. Say you want to play two files at 32000 Hz but the overall output is 44100 Hz. The two 32K files can be mixed, then the mixer can be resampled via a DSP effect (which takes a Sound type as a source), then the DSP sound can be played in the final mixer. (I'm planning on adding SPC support, of which files natively output 32KHz -- however PCs typically don't output that, so resampling will be required in that case)
Making a Mixer a Sound provides all sorts of additional functionality and very little additional code (none, in fact, with the layout I have set up)
StreamedSound and BufferedSound may turn out to be attribute values of a Type attribute of Sound rather than subclasses of Sound. It depends on whether they have their own properties which you want to record. |
Well they both function completely differently. If I have them attributes of the same Sound object then I have to have if/else chains in every Sound function (not to mention bodies for functions which should be pure virtual). The whole point of inheritance/polymorphism is to eliminate that.
What you should do now is describe your system, its entity types (classes) and the relationships between those classes. |
Very well. I have others planned from what's listed here but here's the basics:
- SoundSource: Abstract base class. Takes an input File (or stream) and decodes output to PCM. Various derived objects will support different file types (one for .ogg, one for .wav, one for <insert format here>, etc)
- BufferedSoundData (to be renamed): No parent class. Takes a SoundSource and loads it in full (or in part) to a buffer.
- Sound: Abstract base class, provides volume/fading/panning effects, etc.
- StreamedSound: Derived from Sound, owns a SoundSource object. Progressively reads from given source as audio data is needed.
- BufferedSound: Derived from Sound, owns a BufferedSoundData pointer. Reads data from given sound data pointer
- Mixer: Derived from Sound, owns a list of Sound* pointers. Different Sound* objects are "played" in a mixer (played=added to the list). Mixer simply mixes together all the playing Sound objects and uses the result as its output.
- AudioPlayer / AudioOut (to be renamed): Abstract base class for audio output. Owns a Mixer object. Takes the output of the owned Mixer and outputs it via whatever means. Derived classes will accomplish this with different audio libs (SDL,OAL,ALSA,DS,whathaveyou)
-----
AudioPlayer needs to get the audio output from its owned Mixer object (since Mixer is a Sound, this is via the Sound interface)
Mixer needs to get the audio output from its referenced Sound objects
The lib user will have access to these Sound objects as well (so they can pause/stop them, change pan/volume/etc), so the user still needs access to the interface, but I don't want to the user taking the audio output the way AudioPlayer and Mixer need to.
if you really want to be a system engineer as well as a coder, embark on a relevant course of academic study which will be immensely helpful and rewarding. |
Well I'm working on this project solo for fun in my free time. So there is no "system engineer" other than myself. And as for the "go to school" suggestion: =P
Do not make the 'nannying' of the users of your library a priority. If a user cannot be bothered to read your documentation on how to use your library, then that's their problem. |
So you're saying I should just make the audio output stuff public. I'm actually leaning towards this, as it's the most straightforward solution. Plus who knows, there might even be a time where the user might want to do that for some reason.