Dsaudio

From ProjectWiki
(Difference between revisions)
Jump to: navigation, search
(Initialization and Global Settings)
(iLCgwlRe)
 
(4 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<big>Stuff I'd like to see in the libnds audio implementation</big>
+
That addresses several of my concerns atculaly.
__TOC__
+
<big>Project Status: Drawing board</big>
+
 
+
== Introduction ==
+
 
+
The current libnds audio implementation lacks well most everything. There are only three audio related functions.
+
 
+
This page is for considering what would be the best way to implement full featured audio functionality that makes full use of the DS's wonderful audio hardware and what features would best serve everyone's needs without adding unnecessary bloat to support rarely used functions while hopefully not preventing a developer from adding these features later (without them modifying arm7 code preferably).
+
 
+
Objective of the project overall is to make useful an extensible high quality developer friendly audio library available for DS homebrew... Because, like others, ''need'' or otherwise would like it for my game!!!!! :p
+
 
+
Feel free to comment or [[Talk:Dsaudio|discuss]] concerns or give feedback such as "I'll never use this bit and don't see why anyone else would either", or "I really need this useful feature that can be useful to others.", or anything that comes to mind.
+
 
+
What is here so far is based on discussions [[#References/External Links|on irc]], various libnds and hardware docs on the web [[#References/External Links|like these]].
+
 
+
== Features ==
+
* Sample playback
+
* Load samples from file in raw and wave formats
+
* Dynamic or static allocation of the DS's 16 audio channels.
+
* Basic audio synthesizer using either the PSG/Noise generators or audio samples
+
* efficently using fifo, memory, and cpu balanced against ease of use and flexibility
+
* making full use of the DS's audio hardware, including PSG
+
* adding most common features without causing bloat
+
* no need for end user to modify arm7 code AT ALL
+
* Not suxy :p
+
 
+
== Todo ==
+
Pretty much everything! But more specifically:
+
* Create some type of generalized overview of the complete system
+
* Document/define structures, and types for lib specific return values
+
* Otherwise improve documentation in general
+
* Tho a lot of it is self evident, still need to work out the arm7 side enough to assist in defining an efficient scheme for communication (utilizing the newly added FIFO functionality) between the arm7 and arm9.
+
 
+
== Functions ==
+
So far functions present the arm9 side of things a game/app dev would see.
+
 
+
Cheers pal. I do appercitae the writing.
+
 
+
=== Audio Sample Loading ===
+
all 'Load' commands return mmSample handle or -1 if error
+
most sample loadinging returning u16 value to support up to 65536 samples, however may just use u8 for 256 samples to reduce ram usage. (should be plenty and 65536 is overkill!!)
+
 
+
'''Arguments'''
+
The following argument may be used by functions in this section:
+
rate - sample rate in hertz. For instance 22050, 44100, 9600 are typical values
+
level - volume 0-127
+
pan - pan 0-127
+
flags - various sample flags (see table)
+
start - pointer to start of sample
+
len - sample length in bytes
+
'''Return Values'''
+
Load functions return a handle to the loaded sample as type mmSample. (probably a 16 bit integer). Return value will be negative if function fails.
+
 
+
''' mmSampleDefaults '''
+
<source lang="c">
+
void mmSampleDefaults(int rate, char level, char pan, u8 flags);
+
</source>
+
set default values used by all subsequently 'SimpleLoad'ed samples.
+
 
+
==== Loading From Ram ====
+
''' mmSampleLoad '''
+
<source lang="c">
+
mmSample mmSampleLoad(void *start, int len, void *loopstart, int rate, char level, char pan, u8 flags);
+
</source>
+
 
+
''' mmSampleSimpleLoad '''
+
<source lang="c">
+
mmSample mmSampleSimpleLoad(void *start, int len);
+
</source>
+
 
+
==== Loading From File ====
+
''' mmSampleLoadFile '''
+
<source lang="c">
+
mmSample mmSampleLoadFile(char *file, int rate, char level, char pan, u8 flags);
+
</source>
+
Load sample from filesystem in raw mode.
+
 
+
''' mmSampleSimpleLoadFile '''
+
<source lang="c">
+
mmSample mmSampleSimpleLoadFile(char *file);
+
</source>
+
Load sample from filesystem in raw mode using default values.
+
 
+
''' mmSampleLoadWavFile '''
+
<source lang="c">
+
mmSample mmSampleLoadWavFile(char *file, char level, char pan, u8 flags);
+
</source>
+
riff header is uber ez to parse so why not support .wav format??
+
Load sample from file in wav format.
+
 
+
''' mmSampleSimpleLoadWavFile '''
+
<source lang="c">
+
mmSample mmSampleSimpleLoadWavFile(char *file);
+
</source>
+
Load sample from file in wav format using default values.
+
 
+
==== mmSampleUnload ====
+
<source lang="c">
+
void mmSampleUnload(mmSample sample);
+
</source>
+
stops playing and removes sample from sampletable, and if loaded from file (see below) will free() malloc'd ram..
+
 
+
=== Audio Sample Playback ===
+
'''Arguments'''
+
The following argument may be used by Audio sample playback functions:
+
mmSample - sample handle
+
'''Return Values'''
+
Load functions returns the channel used to play the sample. Return value will be negative if function fails.
+
''' mmSamplePlay '''
+
<source lang="c">
+
char mmSamplePlay(mmSample sample);
+
</source>
+
returns channel mmChan or -1 if no channels available (if stereo sample high nibble contains right channel # and low nibble contains left channel number)
+
 
+
''' mmSampleStop '''
+
<source lang="c">
+
void mmSampleStop(mmSample sample);
+
</source>
+
stops sample on all channels currently using it
+
 
+
''' mmSampleSetRate '''
+
<source lang="c">
+
void mmSampleSetRate(mmSample sample, int rate);
+
</source>
+
 
+
''' mmSampleSetLevel '''
+
<source lang="c">
+
void mmSampleSetLevel(mmSample sample, char level);
+
</source>
+
 
+
''' mmSampleSetPan '''
+
<source lang="c">
+
void mmSampleSetPan(mmSample sample, char pan);
+
</source>
+
 
+
''' mmSampleSetFlags '''
+
<source lang="c">
+
void mmSampleSetFlags(mmSample sample, char flags);
+
</source>
+
ORs Flags? or should just set them??
+
 
+
''' mmSampleClearFlags '''
+
<source lang="c">
+
void mmSampleClearFlags(mmSample sample, char flags);
+
</source>
+
if go with ORing</source>
+
 
+
=== Channel Specific functions ===
+
if mmSamplePlay() reuses the channel 'Set' values are lost
+
mmChan must be 0-15, if stereo sample (and high nibble is used) user is required to mask off upper bits
+
 
+
''' mmChanStop '''
+
<source lang="c">
+
void mmChanStop(char mmChan);
+
</source>
+
stops sample based on the channel
+
 
+
''' mmChanSetRate '''
+
<source lang="c">
+
void mmChanSetRate(char mmChan, int rate);
+
</source>
+
sets sample rate
+
 
+
''' mmChanSetLevel '''
+
<source lang="c">
+
void mmChanSetLevel(char mmChan, u8 level);
+
</source>
+
sets vol of a specified channel
+
 
+
''' mmChanSetPan '''
+
<source lang="c">
+
void mmChanSetPan(char mmChan, char pan);
+
</source>
+
sets pan of specified channel
+
 
+
''' mmChanSetFlags '''
+
<source lang="c">
+
void mmChanSetFlags(char mmChan,u8 flags);
+
</source>
+
sets flags (for instance STICKY, not all flags valid for chans)
+
 
+
''' mmChanSamplePlay '''
+
<source lang="c">
+
void mmChanSamplePlay(char chan, mmSample sample);
+
</source>
+
Prolly normally not used, but if u did want to use a specific channel for a specific reason, here ya go..
+
 
+
''' mmChanGetStatus '''
+
<source lang="c">
+
u8 mmChanGetStatus(char chan);
+
</source>
+
returns channel busy flag and mebbe other things?
+
 
+
=== PSG/NOISE Related Functions ===
+
these may be unnecessary if the synth option is implemented...
+
 
+
''' mmChanPsgNote '''
+
<source lang="c">
+
void mmChanPsgNote(char mmChan, u8 note);
+
</source>
+
Plays specified diatonic note for instance 0=LowestC 12=next octave's C etc etc 0 tru 127 sorta like midi
+
 
+
''' mmChanPsgNote '''
+
<source lang="c">
+
void mmChanPsgNote(char mmChan, u8 note, u8 level, u8 pan,u8 duty);
+
</source>
+
same as above but sets all at once
+
 
+
''' mmChanPsgNoteDetune '''
+
<source lang="c">
+
void mmChanPsgNoteDetune(char mmChan, int amount);
+
</source>
+
Detunes note by specified amount (for pitch bends)
+
 
+
''' mmChanGet '''
+
<source lang="c">
+
char mmChanGet(u8 type);
+
</source>
+
returns a free channel than can be used for psg or whatever (or -1 if none)  type specify to get any free channel, or psg channel, or noise channel using defines below... MAY need to at the same time flag this channel as being in use to prevent arm7 from using it before arm9 gets a chance.. tho only should happen if interrupts or multiprocess?! In that case change name to mmChanAlloc
+
<source lang="c">
+
#define MMGET_ANY 0x0
+
#define MMGET_PSG 0x1
+
#define MMGET_NOISE 0x2
+
</source>
+
 
+
=== Synthesizer Functions ===
+
now would be the time to add synth functions (using the psg/noise and mostly arm7 cpu) such as: AD(SR) envelope generators for volume. A few (4 works for me) LFOs that can be assigned to volume, dutycycle, pitch, or pan of each 'patch'.
+
 
+
''' mmSynthPatchCreatePsg '''
+
<source lang="c">
+
u8 mmSynthPatchCreatePsg(u16 atime, u16 dtime, u8 slevel, u16 rtime, u8 envamount, u16 glidetime, u8 duty, u8 pan, u8 vollfo, u8 dutylfo, u8 pitchlfo, u8 panlfo);
+
</source>
+
Pass this info as a struct?? would save memory that way :)
+
4 lfo params can be combined into one byte if only 4 lfo are available
+
 
+
''' mmSynthPatchCreateNoise '''
+
<source lang="c">
+
u8 mmSynthPatchCreateNoise(u16 atime, u16 dtime, u8 slevel, u16 rtime, u8 envamount, u8 vollfo, u8 dutylfo, u8 panlfo);
+
</source>
+
 
+
''' mmSynthPatchCreateSample '''
+
<source lang="c">
+
u8 mmSynthPatchCreateSample(mmSample sample, u16 atime, u16 dtime, u8 slevel, u16 rtime, u8 envamount, u16 glidetime, u8 pan, u8 vollfo, u8 pitchlfo, u8 panlfo);
+
</source>
+
4 LFO that can be used by a patch to modify various patch params
+
 
+
''' mmSynthLfo '''
+
<source lang="c">
+
void mmSynthLfo(u8 lfo, u8 lfotype, u16 freq, u8 amount);
+
</source>
+
lfo = 0 thru 3 indicating which lfo to adjust. freq = fixed decimal frequency, 8 bits for decimal. amount is the max level , type is either triangle, square (mebbe sawtooth ramp up, ramp down for bomp bomp bomp or womp womp womp effects :)
+
 
+
''' mmSynthNoteOn '''
+
<source lang="c">
+
u8 mmSynthNoteOn(u8 patch, u8 note);
+
</source>
+
returns channel used...
+
 
+
''' mmSynthNoteOnVel '''
+
<source lang="c">
+
u8 mmSynthNoteOnVel(u8 patch, u8 note, u8 velocity);
+
</source>
+
same as above but with velocity (volume) param
+
 
+
''' mmSynthNoteOff '''
+
<source lang="c">
+
void mmSynthNoteOff(u8 patch, u8 note);
+
</source>
+
stops playing note based on patch/note (note u could also use the mmSynthNoteOn()'s return value with mmChanStop() for doing same thing with less overhead);
+
Add mmSynthNoteBend() or just use the mmChanPsgNoteDetune ??? would be less cpu ... dunno
+
 
+
== Defines, Globals, and Structures ==
+
 
+
== Usage Examples ==
+
''' Simplest sample playback scenario '''
+
mmSoundInit(); //Initalize sound lib and set default params (22050khz, PCM8, no loop, mono)
+
mmSamplePlay(mmSampleSimpleLoad((void *)mysample_raw, mysample_len));
+
 
+
Okai, mmSoundInit(); must be called at least once for everything else so im not gonna bother putting in further examples
+
 
+
''' Playing a 44100khz 16bit sample and stopping it after a little bit '''
+
u16 testsample=mmSampleLoad((void *)mysample_raw, mysample_len, NULL, 44100, 127, 64, MMFLAGS_PCM16);
+
mmSamplePlay(testsample);
+
msleep(20000);
+
mmSampleStop(testsample);
+
 
+
''' Playing a sample from filesystem using the default rate/vol/pan/flags '''
+
u16 testsample=mmSampleSimpleLoadFile("/pathto/mysample.raw");
+
mmSamplePlay(testsample);
+
 
+
''' Reusing the same hardware channel to retrig same sample '''
+
u16 testsample=mmSampleSimpleLoad((void*)mysample_raw,mysample_len);
+
u8 samplechan=mmSamplePlay(testsample);
+
doSomethingForABit();
+
mmChanSamplePlay(samplechan,testsample); //reuse same channel
+
 
+
Alternate way to do sorta same thing, in this case make a imaginary spaceship's laser firing noise:
+
u16 shipshootsample=mmSampleSimpleLoad((void*)mysample_raw,mysample_len);
+
u8 shipshootchannel=mmChanGet(MMGET_ANY); //Get an unused sample channel
+
mmChanSetFlags(MMFLAGS_STICKY); //optional, used to indicate this channel shouldnt be dynamically allocated to other sounds
+
while(1) {
+
  if(shipgotshot) {
+
  mmChanSamplePlay(shipshootchannel,shipshootsample);
+
  }
+
};
+
 
+
== References/External Links ==
+
Hardware references and other DS audio libraries<br />
+
[http://ekid.nintendev.com/sekrit/reference.htm Maxmod library] It would be nice if this was merged or at least compatible with eKids's project.<br />
+
[http://nocash.emubase.de/gbatek.htm#dssound gbatek sound]<br />
+
[http://neimod.com/dstek/ neimod]<br />
+
[http://blitzed.org #dsdev@irc.blitzed.org]
+
 
+
== Example Header ==
+
[[Dsaudio:Example_header|Mostly useless outdated header example can be found here.]] Original notes related to implementing an audio library written in .c syntax. This wiki page represents a more refined version of these header notes.  
+
 
+
[[Category:NDS]]
+

Latest revision as of 07:09, 8 January 2012

That addresses several of my concerns atculaly.

Personal tools
irssi scripts
eggdrop scripts