This module contains the routines to turn a song into a stream of floating point samples. Some intermediate structures are also made available to allow more fine-grain control over playback.
- sampleFrequency :: Float
- data Sample = Smp {
- leftChannel :: !Float
- rightChannel :: !Float
- data PlayState = PS {
- psTempo :: Int
- psBPM :: Int
- psRow :: Maybe [Note]
- psChannels :: [ChannelState]
- startState :: Int -> PlayState
- data ChannelState = CS {
- csWaveData :: WaveData
- csPeriod :: Int
- csFineTune :: Float
- csSubSample :: Float
- csSampleStep :: Float
- csVolume :: Float
- csInstrument :: Instrument
- csEffect :: [Effect]
- csPanning :: Float
- csPortaDown :: Int
- csPortaUp :: Int
- csFinePorta :: Int
- csTonePortaEnd :: Int
- csTonePortaSpeed :: Int
- csVolumeSlide :: Float
- csFineVolumeSlide :: Float
- csVibratoSpeed :: Int
- csVibratoAmp :: Float
- csVibratoWave :: [Float]
- csTremoloSpeed :: Int
- csTremoloAmp :: Float
- csTremoloWave :: [Float]
- csTremoloDiff :: Float
- csDelayedPeriod :: Int
- csDelayedInstrument :: Instrument
- type ChunkMixState = (Int, [(WaveData, Float, Int, Float, Float, Float)])
- type SongMixState = [ChunkMixState]
- prepareMix :: PlayState -> ChunkMixState
- mixToBuffer :: Ptr Float -> Int -> SongMixState -> IO (Maybe SongMixState)
- nextSample :: ChunkMixState -> Maybe (Sample, ChunkMixState)
- mixSong :: Song -> [(PlayState, [Sample])]
- mixChunk :: PlayState -> [Sample]
- performSong :: Song -> [PlayState]
- flattenSong :: Song -> [[Note]]
- performTicks :: [[Note]] -> [PlayState]
Output format
sampleFrequency :: FloatSource
The frequency at which mixer output should be played back. For the time being, this is a fixed value.
Smp | |
|
Player and mixer state
The state of the player upon entering a tick.
startState :: Int -> PlayStateSource
The initial state of the player given the number of channels.
data ChannelState Source
The state of a channel upon entering a tick.
CS | |
|
type SongMixState = [ChunkMixState]Source
Sample-level mixing routines
prepareMix :: PlayState -> ChunkMixStateSource
Create a mixer state from a player state. This basically strips away a lot of unnecessary information and throws away the channels that don't contribute to the output in the given chunk.
mixToBuffer :: Ptr Float -> Int -> SongMixState -> IO (Maybe SongMixState)Source
Given a pointer to a float buffer and a number of samples desired
(n), mix the appropriate amount of the song and return the mix
state for the remainder or Nothing
if finished. This is the most
efficient way to render a song. Note that each sample consists of
two floats, so the buffer has to be able to hold 2*n floats. The
initial song mix state can be simply created by
.
map
prepareMix
. performSong
nextSample :: ChunkMixState -> Maybe (Sample, ChunkMixState)Source
Mix a single sample given a chunk mix state. Returns Nothing
at the end of the chunk.
Mixing whole songs
mixSong :: Song -> [(PlayState, [Sample])]Source
Mix a whole song in chunks, pairing up the play states with the respective chunks.
mixChunk :: PlayState -> [Sample]Source
Mix a single chunk given a play state. It's equivalent to
.
unfoldr
nextSample
. prepareMix
performSong :: Song -> [PlayState]Source
Turn a song into a series of play states, one for each tick.
It's a shorthand for
.
performTicks
. flattenSong
flattenSong :: Song -> [[Note]]Source
Turn a song into a series of pattern rows. This includes handling control structures like pattern breaks, delays and loops. Order jumps are ignored.
performTicks :: [[Note]] -> [PlayState]Source
Turn a list of rows into a list of play states. Each row gives birth to a number of play states equal to the tempo on that row.