/*------------------------------------------------------------------------------ -----------------
Copyright J.Hubert 2015
This file is part of demOS
demOS is free software: you can redistribute it and/or modify it under the terms of
the GNU Lesser General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
demOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY ;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with demOS.
If not, see .
------------------------------------------------------------------------------------------------- */
/*! @brief @ref SND @file */
/*! @defgroup SND
SND provides SouNDtrack management.
It is designed to be cheap in terms of CPU usage.
SND:
- plays PCM sample with STe DMA
- manages volumes of left / right channels : the idea is to listen in mono
and use them as (free) mixers
- manages the musical score as a DSL code (coded as a co-routine)
- requires / synchronizes loading of samples and transfer PCM to the wished channel
Volume slides are managed by VBL interrupt
PCM transfers are also sliced into VBL interrupt.
*/
#ifndef SOUND_H
#define SOUND_H
#include "DEMOSDK\BASTYPES.H"
#include "DEMOSDK\HARDWARE.H"
#include "DEMOSDK\ALLOC.H"
#include "DEMOSDK\LOAD.H"
extern volatile u8 SNDleftVolume;
extern volatile u8 SNDrightVolume;
extern volatile s8 SNDfademasterVolume;
extern volatile u8 SNDspeedfade;
extern volatile u16 SNDdmaLoopCount;
extern void* SNDsourceTransfer;
extern volatile void* SNDendSourceTransfer;
extern void* SNDdestTransfer;
extern volatile void* SNDlastDMAposition; /* read only */
extern volatile s8 SNDmasterVolume; /* ready only - debug purpose */
STRUCT(SNDcore)
{
u8* dmaBuffer;
u8* cache;
u32 sampleLength;
bool pcmLoaded;
bool syncWithSoundtrack;
LOADrequest* currentLoadRequest;
u16 dmaLoopstart;
volatile s16 playerContext;
u16 playerStart;
volatile u16 playerClientStep;
};
#ifndef SOUND_C
extern SNDcore snd;
extern u8 SNDchannelVolume[];
#endif
#define SND_BEGIN case 0: snd.playerStart = __LINE__;
#define SND_LOADSAMPLE(MEDIA,RESOURCE) snd.currentLoadRequest = LOADrequestLoad(&RSC_##MEDIA##, RSC_##MEDIA##_ZIK__##RESOURCE##_RAW, snd.cache, LOAD_PRIOTITY_HIGH);
#define SND_WAIT_SAMPLELOADED case __LINE__: if ( snd.currentLoadRequest->processed == false ) return __LINE__; snd.currentLoadRequest->allocated = false; snd.currentLoadRequest = NULL;
#define SND_SYNC_COPYCACHE_TO_LEFT(OFFSET,LEN) SNDcopySample(snd.cache, snd.dmaBuffer + (OFFSET << 1) , LEN);
#define SND_SYNC_COPYCACHE_TO_RIGHT(OFFSET,LEN) SNDcopySample(snd.cache, snd.dmaBuffer + (OFFSET << 1) +1 , LEN);
#define SND_COPYCACHE_TO_LEFT(OFFSET,LEN) SNDsourceTransfer = snd.cache; SNDendSourceTransfer = snd.cache + LEN; SNDdestTransfer = snd.dmaBuffer + (OFFSET << 1);
#define SND_COPYCACHE_TO_RIGHT(OFFSET,LEN) SNDsourceTransfer = snd.cache; SNDendSourceTransfer = snd.cache + LEN; SNDdestTransfer = snd.dmaBuffer + (OFFSET << 1) + 1;
#define SND_WAIT_CACHECOPIED case __LINE__: if ( SNDsourceTransfer < SNDendSourceTransfer ) return __LINE__;
#define SND_VOLUME_SET(VOL) SNDmasterVolume = VOL; (*HW_MICROWIRE_MASK) = HW_MICROWIRE_MASK_SOUND; (*HW_MICROWIRE_DATA) = HW_MICROWIRE_VOLUME | VOL;
#define SND_VOLUME_FADEIN(STEP) SNDspeedfade = STEP; SNDmasterVolume = 0; SNDfademasterVolume = 1;
#define SND_VOLUME_FADEOUT(STEP) SNDspeedfade = STEP; SNDmasterVolume = 40; SNDfademasterVolume = -1;
#define SND_SETPANNING(PAN) SNDleftVolume = SNDchannelVolume[PAN]; SNDrightVolume = SNDchannelVolume[6 - PAN]; { STATIC_ASSERT(PAN<7); }
#define SND_DMALOOP_RESET snd.dmaLoopstart = SNDdmaLoopCount;
#define SND_WAIT_DMALOOP_REACH(COUNT) case __LINE__: if ( (SNDdmaLoopCount - snd.dmaLoopstart) < COUNT ) return __LINE__;
#define SND_IDLE case __LINE__: return __LINE__;
#define SND_RESTART return 0;
#define SND_WAIT_CLIENTSTEP(COUNT) case __LINE__: if (( snd.playerClientStep < COUNT ) && snd.syncWithSoundtrack ) return __LINE__;
void SNDinit (RINGallocator* _allocator, u32 _sampleLen);
void SNDshutdown (RINGallocator* _allocator);
void SNDcopySample (u8* _source, u8* _dest, u32 _length);
void SNDwaitDMALoop (void);
void SNDwaitClientStep(u16 _clientStep); /* shoud be used from idle thread only ! */
void SNDplayNoise (u16 _freq, u16 _level);
void SNDstopNoise (void);
#ifdef DEMOS_DEBUG
u16 SNDtrace (void* _image, u16 _pitch, u16 _planePitch, u16 _y);
#endif
#endif