add clinkster source (doesn't seem to have a public git repo)
This commit is contained in:
parent
43cccc563e
commit
718ba6f4f2
|
@ -0,0 +1 @@
|
|||
clinkster/Clinkster/* linguist-vendored
|
|
@ -0,0 +1 @@
|
|||
*.o
|
|
@ -0,0 +1,205 @@
|
|||
|
||||
CLINKSTER - a software synthesizer for 4k intros by Blueberry / Loonies
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
Clinkster is a software synthesizer (or synth, for short) designed for use in
|
||||
extremely size-restricted executables, such a 4k intros. It has been under
|
||||
development since 2008 and used in several 4k intros through the years. For
|
||||
some background reading on the ideas behind it and its early history, refer
|
||||
to the article from Zine #14 "Development Diary of Luminagia":
|
||||
http://zine.bitfellas.org/article.php?zine=14&id=24
|
||||
|
||||
|
||||
FEATURES
|
||||
|
||||
- VST instrument for Windows and Mac OS X, with source
|
||||
- Simple interface: create your instruments using just 18 sliders
|
||||
- Multi-layered, delicious, voluminous stereo sound based on phase modulation
|
||||
- Unlimited number of tracks and unlimited polyphony per track
|
||||
- Player source for Windows - integrate with C++ or asm
|
||||
- Excludes unused features from player code to save space
|
||||
- Easy-exe setup for creating executable music - no coding or additional
|
||||
installation needed
|
||||
- Many example songs and instruments included
|
||||
|
||||
|
||||
OVERVIEW
|
||||
|
||||
The Clinkster toolchain consists of three parts:
|
||||
|
||||
1. A VST instrument to use when composing the music. This can in principle be
|
||||
used with any VSTi host, but the rest of the toolchain is designed to be
|
||||
used with Renoise, so if you want to use your music in an executable, you
|
||||
will need to make your music in Renoise.
|
||||
|
||||
2. A conversion script - RenoiseConvert.py - to convert a Renoise song using
|
||||
Clinkster instruments into a .asm file containing the music data in the
|
||||
format needed by the executable player. To run the conversion script, you
|
||||
will need to install Python 2.x (where x >= 5).
|
||||
|
||||
3. Player code to include in your intro. Two versions are provided:
|
||||
clinkster.asm and clinkster_multithreaded.asm. The multithreaded version
|
||||
is bigger but computes the music twice as fast (provided you have at least
|
||||
two CPU cores). Both of these assume the converted music in music.asm.
|
||||
The clinkster.h and clinkster.inc files contain definitions for using the
|
||||
synth from C/C++ or asm, respectively. Refer to these files for detailed
|
||||
usage information.
|
||||
|
||||
|
||||
PARAMETERS
|
||||
|
||||
Clinkster is designed to be used with the built-in VST parameter adjustment
|
||||
GUI in Renoise.
|
||||
|
||||
The numbers in parentheses after the value of each parameter indicates the
|
||||
byte value that will be used to represent that parameter value in the
|
||||
executable version of the music. Using the same byte values across parameters
|
||||
and across instruments generally leads to a more compact representation of the
|
||||
music.
|
||||
|
||||
The sliders in Renoise have 101 different positions, and for most of the
|
||||
parameters, these correspond to successive byte values. The exceptions are:
|
||||
- B PitchD, M PitchD, IndexD, Attack, Decay, Release, Gain: One position for
|
||||
every two values.
|
||||
- B Pitch and M Pitch: 5 positions for every 12 values (one octave).
|
||||
- RandomSeed: 128 values in total.
|
||||
|
||||
If you want a value in between two slider-accessible values, click on the
|
||||
value to access the internal representation (0% for minimum, 100% for maximum)
|
||||
and modify it slightly.
|
||||
|
||||
As for the meaning of the individual parameters, experimentation is the key.
|
||||
Be sure to test your instrument in many different octaves. To get you started,
|
||||
here is a brief description of the parameters:
|
||||
|
||||
BaseWave, ModWave: Waveforms for the two oscillators. The ModWave modulates
|
||||
the phase of the BaseWave.
|
||||
B Detune, M Detune: Randomly varies the frequencies of the two oscillators
|
||||
across layers and across the left and right channel.
|
||||
B Pitch, M Pitch: Pitch the oscillator up or down relative to the played note.
|
||||
B PitchD, M PitchD (pitch decay): Decay the pitch towards (or away from) the
|
||||
played note.
|
||||
Index: Strength of the phase modulation.
|
||||
IndexSpr (index spread): Randomly varies the modulation strength across layers
|
||||
and across the left and right channel.
|
||||
IndexD (index decay): Decay the modulation strength towards (or away from)
|
||||
zero.
|
||||
Layers: Number of layers of sound to compute, with individual, random
|
||||
variations controlled by the detune and index spread parameters. More
|
||||
layers give a fatter, more chorus-like sound but also increases the
|
||||
computational load of the instrument considerably.
|
||||
RandomSeed: Seed used for the random variations across layers and channels.
|
||||
Adjust this until you get a balanced, in-key sound.
|
||||
Attack, Decay, Sustain, Release: Control the amplitude envelope of the sound.
|
||||
Setting Sustain to a negative value creates a "double attack" where the
|
||||
amplitude crosses zero during the decay.
|
||||
Gain: Amplify the sound after the amplitude envelope and apply soft clipping.
|
||||
Results in distorted or compressed sounds.
|
||||
|
||||
Also take a look at the included example instruments and example songs for
|
||||
inspiration.
|
||||
|
||||
|
||||
USING THE VST
|
||||
|
||||
In order to use the music in an executable, there are a couple of guidelines
|
||||
you need to follow when creating your music in Renoise.
|
||||
|
||||
You can use per-note velocity, but no other in-track effect commands.
|
||||
|
||||
You can use any number of tracks and any number of note columns per track.
|
||||
|
||||
You can adjust the volume and panning of tracks using the Volume/Panning Track
|
||||
DSP, the post-DSP volume/panning, the mixer and the master volume.
|
||||
|
||||
You can use the Delay effect (under Track DSPs) with these restrictions:
|
||||
- The "L Feedb.", "R Feedb." and "Send" sliders must be at the same position.
|
||||
- "Mute Src." must be off.
|
||||
- No L/R Output Pan.
|
||||
- If you use the Delay effect on multiple tracks, you must use the exact same
|
||||
parameters on each track.
|
||||
|
||||
To make it easier to control the volume and panning of a group of tracks, or
|
||||
to use the same delay on multiple tracks, you can use a #Send DSP set to "Mute
|
||||
Source" to route the sound from the track to a Send track. You can then set
|
||||
the desired volume, panning and delay on the Send track. Only the final track
|
||||
of a Send chain can use delay.
|
||||
|
||||
The VST is designed to run in one instance per instrument and supports
|
||||
unlimited polyphony and unlimited reuse of instruments across tracks. Note
|
||||
however, that if you play notes using the same instrument in multiple tracks
|
||||
at the same time, Renoise will play the notes using a single VST instance and
|
||||
output the result in the track in which the last note was triggered. This
|
||||
works fine as long as the tracks use the same volume, panning and delay. If
|
||||
this is not the case, you will need to use separate copies of the instrument
|
||||
for each different track. Otherwise, you will get clicks and generally a
|
||||
different result from what you expected.
|
||||
|
||||
In the pattern sequence matrix (available to the left of the pattern view),
|
||||
you can mute individual tracks at specific positions. This muting is taken
|
||||
into account by the converter.
|
||||
|
||||
The VST works with any sample rate. To match the sound produced by the player,
|
||||
use a sample rate of 44100Hz. If your music is too computationally heavy for
|
||||
your CPU to cope with, you can lighten the load by lowering the sample rate
|
||||
while composing, though that will of course have a detrimental effect on the
|
||||
sound quality.
|
||||
|
||||
|
||||
USING THE CONVERTER
|
||||
|
||||
The RenoiseConvert.py script in the converter directory (or, equivalently,
|
||||
RenoiseConvert.exe in easy_exe/tools) will convert a Renoise song using
|
||||
Clinkster into a .asm file to use with the supplied player source.
|
||||
|
||||
During conversion, each note column in a track will become a separate track in
|
||||
the converted music. If you use more than one instrument inside a single note
|
||||
column, that column will be split by the converter into one track per
|
||||
instrument. Also, if you have used the delay effect, all tracks using delay
|
||||
will be put before the tracks not using delay.
|
||||
|
||||
The converter will print a list of the resulting tracks, along with the
|
||||
original track / instrument combinations they correspond to.
|
||||
|
||||
For each track, it will print a list of tone / length / velocity combinations
|
||||
used in that track, in the form NOTE/VELOCITY:LENGTH(NUMBER) or
|
||||
NOTE:LENGTH(NUMBER). For instance, C-4/6A:4(32) means that C-4 notes with
|
||||
velocity 6A (hex) and length 4 occur 32 times in the track. If the velocity is
|
||||
omitted, it is 127 (7F hex - maximum). The number of different combinations
|
||||
used in the track has influence on the size of the resulting music (as well as
|
||||
its precalculation time), so this list can be useful as a guide for optimizing
|
||||
your music to take up less space.
|
||||
|
||||
At the end, the converter prints a list of the optional features used in the
|
||||
music. Each of these features has some cost in terms of the code size of the
|
||||
player. The options are:
|
||||
|
||||
SINE, SAWTOOTH, SQUARE, PARABOLA, TRIANGLE, NOISE:
|
||||
The corresponding waveform is used in some instrument.
|
||||
VELOCITY: One or more notes have velocity less than 127.
|
||||
LONG_NOTES: One or more notes are longer than 127 rows.
|
||||
DELAY: The delay device is used.
|
||||
PANNING: One or more tracks have non-center panning.
|
||||
INDEXDECAY: Some instrument has IndexDecay different from 0.
|
||||
GAIN: Some instrument has Gain different from 1.
|
||||
|
||||
|
||||
FEEDBACK
|
||||
|
||||
I am always very interested in hearing about your adventures with Clinkster,
|
||||
and to help out if you encounter problems.
|
||||
|
||||
Send stories, comments, bug reports and questions to blueberry@loonies.dk or
|
||||
post them to the Pouet forum at http://pouet.net/prod.php?which=61592
|
||||
|
||||
|
||||
ACKNOWLEDGEMENTS
|
||||
|
||||
Thanks to all the people who have tried out this synth (as musician and/or
|
||||
coder) and given good feedback for its development: Bod, Bstrr, Curt Cool,
|
||||
Eladamri, El Blanco, Farfar, Garfferen, Hardy, Lemmus, Loaderror, Maytz,
|
||||
Neoman, Psycho, Punqtured, Response, Seven, TheT, Xerxes, and the ones I
|
||||
have forgotten.
|
||||
|
|
@ -0,0 +1,665 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import zipfile
|
||||
import XML
|
||||
import struct
|
||||
import ctypes
|
||||
import math
|
||||
import datetime
|
||||
|
||||
class InputException(Exception):
|
||||
def __init__(self, message):
|
||||
Exception.__init__(self)
|
||||
self.message = message
|
||||
|
||||
|
||||
class Volume:
|
||||
def __init__(self, left, right):
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def __mul__(self, other):
|
||||
return Volume(self.left * other.left, self.right * other.right)
|
||||
|
||||
def isPanned(self):
|
||||
return self.left != self.right
|
||||
|
||||
def makeVolume(xvolume):
|
||||
v = float(xvolume)
|
||||
return Volume(v,v)
|
||||
|
||||
def makePanning(xpanning):
|
||||
p = float(xpanning)
|
||||
return Volume(math.sqrt(2.0 * (1.0 - p)), math.sqrt(2.0 * p))
|
||||
|
||||
|
||||
|
||||
class Instrument:
|
||||
NAMES = ["bwave","mwave","bdetune","mdetune",
|
||||
"bpitchs","bpitchd","mpitchs","mpitchd",
|
||||
"index","indexspr","indexd","layers","randomseed",
|
||||
"attack","decay","sustain","release","gain"]
|
||||
QUAN = [(6,0),(6,0),(101,0),(101,0),
|
||||
(241,120),(201,128),(241,120),(201,128),
|
||||
(101,0),(101,0),(201,128),(51,0),(128,0),
|
||||
(201,128),(201,128),(65,32),(201,128),(201,80)]
|
||||
|
||||
def __init__(self, number, name, params):
|
||||
names,quan = Instrument.NAMES,Instrument.QUAN
|
||||
self.number = number
|
||||
self.name = name
|
||||
self.params = params
|
||||
self.param_data = [int(p * (quan[i][0]-1) + 0.5) - quan[i][1] for i,p in enumerate(params)]
|
||||
for i,p in enumerate(self.param_data):
|
||||
self.__dict__[names[i]] = p
|
||||
for mp,m in [("layers", 1), ("attack", -120), ("decay", -120), ("release", -120)]:
|
||||
if self.__dict__[mp] < m:
|
||||
self.__dict__[mp] = m
|
||||
print " * Instrument '%s': %s clamped to %d" % (name, mp, m)
|
||||
self.chopped = self.sustain == 0
|
||||
self.volume = Volume(1.0, 1.0)
|
||||
|
||||
class Note:
|
||||
NOTEBASES = {
|
||||
"C": 0, "D": 2, "E": 4, "F": 5, "G": 7, "A": 9, "B": 11
|
||||
}
|
||||
|
||||
NOTENAMES = {
|
||||
0: "C-", 1: "C#", 2: "D-", 3: "D#", 4: "E-", 5: "F-",
|
||||
6: "F#", 7: "G-", 8: "G#", 9: "A-", 10: "A#", 11: "B-"
|
||||
}
|
||||
|
||||
def __init__(self, line, songpos, pat, note, instr, velocity):
|
||||
note = str(note)
|
||||
self.line = int(line)
|
||||
self.songpos = int(songpos)
|
||||
self.pat = int(pat)
|
||||
self.velocity = 127 if str(velocity) == "" or str(velocity) == ".." else int(str(velocity), 16)
|
||||
if note == "OFF":
|
||||
self.off = True
|
||||
self.tone = None
|
||||
self.instr = 0
|
||||
else:
|
||||
self.off = False
|
||||
octave = int(note[2])
|
||||
notebase = Note.NOTEBASES[note[0]]
|
||||
sharp = int(note[1] == "#")
|
||||
self.tone = octave * 12 + notebase + sharp
|
||||
self.instr = int(str(instr), 16)
|
||||
|
||||
|
||||
def instplugins(xinst):
|
||||
xplugins = xinst.PluginProperties
|
||||
if xplugins:
|
||||
return xplugins
|
||||
return xinst.PluginGenerator
|
||||
|
||||
def isactive(xdevice):
|
||||
if not xdevice:
|
||||
return False
|
||||
if xdevice.IsActive.Value:
|
||||
return float(xdevice.IsActive.Value) != 0.0
|
||||
else:
|
||||
return str(xdevice.IsActive) == "true"
|
||||
|
||||
def notename(tone):
|
||||
return Note.NOTENAMES[tone%12] + str(tone/12)
|
||||
|
||||
def multibyte(v):
|
||||
return [-1 - (v >> 8), v & 255] if v > 127 else [v]
|
||||
|
||||
|
||||
class Track:
|
||||
def __init__(self, number, name, notes, volume, instr, instruments):
|
||||
self.number = number
|
||||
self.name = name
|
||||
self.notes = notes
|
||||
self.volume = volume * instruments[instr].volume
|
||||
self.instr = instr
|
||||
self.notemap = dict()
|
||||
self.tal_repr = dict()
|
||||
|
||||
prev = None
|
||||
for note in notes:
|
||||
if prev is not None and not prev.off and prev.instr == instr:
|
||||
length = 1 if instruments[self.instr].chopped else note.line - prev.line
|
||||
if length < 0:
|
||||
raise InputException("Track '%s' has reversed note order from %d to %d" % (name, prev.line, note.line))
|
||||
if prev.tone is None:
|
||||
raise InputException("Track '%s' has a toneless note at %d" % (name, prev.line))
|
||||
tal = (prev.tone, length, prev.velocity)
|
||||
self.notemap[prev] = tal
|
||||
|
||||
prev = note
|
||||
|
||||
if not prev.off and prev.instr == instr:
|
||||
if instr.chopped:
|
||||
tal = (prev.tone, 1)
|
||||
self.notemap[prev] = tal
|
||||
elif not prev.off:
|
||||
raise InputException("Track '%s' is not terminated." % name)
|
||||
|
||||
self.tals = sorted(set(self.notemap.values()), key = (lambda (t,l,v) : (t,v,-l)))
|
||||
for i,tal in enumerate(self.tals):
|
||||
if tal[0] is None:
|
||||
raise InputException("Track '%s' has a toneless note" % name)
|
||||
self.tal_repr[tal] = i
|
||||
|
||||
self.longest_sample = None
|
||||
self.sample_length_sum = None
|
||||
|
||||
|
||||
class Music:
|
||||
def __init__(self, version, tracks, instruments, length, ticklength, n_delay_tracks, delay_lengths, delay_strength, master_volume):
|
||||
self.version = version
|
||||
self.tracks = tracks
|
||||
self.instruments = instruments
|
||||
self.length = length
|
||||
self.ticklength = ticklength
|
||||
self.n_delay_tracks = n_delay_tracks
|
||||
self.delay_lengths = delay_lengths
|
||||
self.delay_strength = delay_strength
|
||||
self.master_volume = master_volume
|
||||
|
||||
self.uses_waveform = [False] * 6
|
||||
for t in self.tracks:
|
||||
inst = self.instruments[t.instr]
|
||||
self.uses_waveform[inst.bwave] = True
|
||||
self.uses_waveform[inst.mwave] = True
|
||||
self.uses_velocity = any(any(tal[2] != 127 for tal in t.tals) for t in self.tracks)
|
||||
self.uses_long_notes = any(any(tal[1] > 127 for tal in t.tals) for t in self.tracks)
|
||||
self.uses_delay = (self.n_delay_tracks > 0)
|
||||
self.uses_panning = any(t.volume.isPanned() for t in self.tracks)
|
||||
self.uses_indexdecay = any(self.instruments[t.instr].indexd != 0 for t in self.tracks)
|
||||
self.uses_gain = any(self.instruments[t.instr].gain != 0 for t in self.tracks)
|
||||
|
||||
# Calculate longest sample
|
||||
self.max_longest_sample = 0.0
|
||||
self.max_sample_length_sum = 0.0
|
||||
self.max_release_tail = 0.0
|
||||
for ti,track in enumerate(self.tracks):
|
||||
track.longest_sample = 0.0
|
||||
track.sample_length_sum = 0.0
|
||||
track.max_release_tail = 0.0
|
||||
|
||||
def envelope(v):
|
||||
return pow(2.0, v * 0.125) * 32767.0 / (44100.0 * 4)
|
||||
instr = instruments[track.instr]
|
||||
attack_length = envelope(instr.attack)
|
||||
decay_length = envelope(instr.decay)
|
||||
release_length = envelope(instr.release)
|
||||
|
||||
for tal in track.tals:
|
||||
note_length = tal[1] * ticklength
|
||||
sustain_length = max(note_length, attack_length + decay_length)
|
||||
sample_length = sustain_length + release_length + 32767.0 / (44100.0 * 4) + 0.01
|
||||
release_tail = sample_length - note_length
|
||||
track.longest_sample = max(track.longest_sample, sample_length)
|
||||
track.sample_length_sum += sample_length
|
||||
track.max_release_tail = max(track.max_release_tail, release_tail)
|
||||
self.max_longest_sample = max(self.max_longest_sample, track.longest_sample)
|
||||
self.max_sample_length_sum = max(self.max_sample_length_sum, track.sample_length_sum)
|
||||
self.max_release_tail = max(self.max_release_tail, track.max_release_tail)
|
||||
|
||||
# Track title, specifying resulting track index, track name and instrument number / name
|
||||
instr = self.instruments[track.instr]
|
||||
track.title = "%02d: %s / %02X|%s" % (ti, track.name, instr.number, instr.name)
|
||||
|
||||
self.datainit = None
|
||||
self.out = None
|
||||
|
||||
def dataline(self, data):
|
||||
if len(data) > 0:
|
||||
line = self.datainit
|
||||
first = True
|
||||
for d in data:
|
||||
if not first:
|
||||
line += ","
|
||||
line += str(d)
|
||||
first = False
|
||||
line += "\n"
|
||||
self.out += line
|
||||
|
||||
def instrparams(self, inst, fields):
|
||||
return [inst.__dict__[f] if f in inst.__dict__ else f for f in fields]
|
||||
|
||||
def comment(self, c):
|
||||
self.out += "\t; %s\n" % c
|
||||
|
||||
def notelist(self, datafunc, trackterm):
|
||||
for t in self.tracks:
|
||||
self.comment(t.title)
|
||||
prev_n = None
|
||||
pat_data = []
|
||||
for n in [note for note in t.notes if not note.off and note.instr == t.instr]:
|
||||
if prev_n is None or n.songpos != prev_n.songpos:
|
||||
self.dataline(pat_data)
|
||||
pat_data = []
|
||||
self.comment("position %d - pattern %d" % (n.songpos, n.pat))
|
||||
pat_data += datafunc(t,prev_n,n)
|
||||
prev_n = n
|
||||
self.dataline(pat_data)
|
||||
self.dataline(trackterm)
|
||||
self.out += "\n"
|
||||
|
||||
def notebitmask(self):
|
||||
for t in self.tracks:
|
||||
self.comment(t.name)
|
||||
prev_n = None
|
||||
pat_data = []
|
||||
pos = 0
|
||||
data_byte = 0
|
||||
dummy_note = Note(self.length, 0, 0, "C-0", 0, 127)
|
||||
for n in [note for note in t.notes if not note.off and note.instr == t.instr] + [dummy_note]:
|
||||
while pos <= n.line:
|
||||
data_byte = (data_byte << 1) + (1 if pos == n.line else 0)
|
||||
pos += 1
|
||||
if (pos & 7) == 0:
|
||||
if prev_n is None or n.songpos != prev_n.songpos:
|
||||
self.dataline(pat_data)
|
||||
pat_data = []
|
||||
self.comment("position %d - pattern %d" % (n.songpos, n.pat))
|
||||
prev_n = n
|
||||
pat_data.append(data_byte)
|
||||
data_byte = 0
|
||||
prev_n = n
|
||||
self.dataline(pat_data)
|
||||
self.out += "\n"
|
||||
|
||||
def posdata(self, t, pn, n):
|
||||
step = n.line-pn.line if pn is not None else n.line
|
||||
return multibyte(step)
|
||||
|
||||
def samdata(self, t, pn, n):
|
||||
return [t.tal_repr[t.notemap[n]]]
|
||||
|
||||
def exportPC(self, sample_rate):
|
||||
self.datainit = "\tdb\t"
|
||||
self.out = ""
|
||||
|
||||
sspt = int(self.ticklength * sample_rate)*4
|
||||
|
||||
def roundup(v):
|
||||
return (int(v) & -0x10000) + 0x10000
|
||||
|
||||
feature_flags = self.uses_waveform + [self.uses_velocity, self.uses_long_notes, self.uses_delay, self.uses_panning, self.uses_indexdecay, self.uses_gain]
|
||||
feature_names = ["SINE", "SAWTOOTH", "SQUARE", "PARABOLA", "TRIANGLE", "NOISE",
|
||||
"VELOCITY", "LONG_NOTES", "DELAY", "PANNING", "INDEXDECAY", "GAIN"]
|
||||
print "Features used: " + " ".join(n for f,n in zip(feature_flags, feature_names) if f)
|
||||
print
|
||||
|
||||
global infile
|
||||
self.out += "; Clinkster music converted from %s %s\n" % (infile, str(datetime.datetime.now())[:-7])
|
||||
self.out += "\n"
|
||||
for f,fname in zip(feature_flags, feature_names):
|
||||
self.out += "%%define USES_%s %d\n" % (fname, int(f))
|
||||
self.out += "\n"
|
||||
self.out += "%%define SUBSAMPLES_PER_TICK %d\n" % sspt
|
||||
self.out += "%%define MAX_INSTRUMENT_SUBSAMPLES %d\n" % roundup((self.max_longest_sample + self.max_release_tail) * (sample_rate * 4.0))
|
||||
self.out += "%%define MAX_TOTAL_INSTRUMENT_SAMPLES %d\n" % roundup(self.max_sample_length_sum * sample_rate)
|
||||
self.out += "%%define MAX_RELEASE_SUBSAMPLES %d\n" % roundup(self.max_release_tail * (sample_rate * 4.0))
|
||||
self.out += "%%define TOTAL_SAMPLES %d\n" % roundup((self.length * self.ticklength + self.max_release_tail) * sample_rate)
|
||||
self.out += "%%define MAX_TRACK_INSTRUMENT_RENDERS %d\n" % max(len(t.tals) for t in self.tracks)
|
||||
self.out += "\n"
|
||||
self.out += "%%define MAX_DELAY_LENGTH %d\n" % int(max(self.delay_lengths) * sample_rate)
|
||||
self.out += "%%define LEFT_DELAY_LENGTH %d\n" % int(self.delay_lengths[0] * sample_rate)
|
||||
self.out += "%%define RIGHT_DELAY_LENGTH %d\n" % int(self.delay_lengths[1] * sample_rate)
|
||||
self.out += "%%define DELAY_STRENGTH %0.8f\n" % self.delay_strength
|
||||
self.out += "\n"
|
||||
self.out += "%%define NUMTRACKS %d\n" % len(self.tracks)
|
||||
self.out += "%%define LOGNUMTICKS %d\n" % int(math.log(self.length, 2) + 1)
|
||||
self.out += "%%define MUSIC_LENGTH %d\n" % self.length
|
||||
self.out += "%%define TICKS_PER_SECOND %0.8f\n" % (1.0 / self.ticklength)
|
||||
|
||||
# Remap used instruments
|
||||
wmap = []
|
||||
j = 0
|
||||
for i in range(6):
|
||||
wmap.append(j)
|
||||
if self.uses_waveform[i]:
|
||||
j += 1
|
||||
for inst in self.instruments:
|
||||
if inst is not None:
|
||||
for wave in ["bwave", "mwave"]:
|
||||
inst.__dict__[wave] = wmap[inst.__dict__[wave]]
|
||||
|
||||
# Instrument data
|
||||
self.out += "\n\n\tsection instdata data align=1\n"
|
||||
self.out += "\n_InstrumentData:\n"
|
||||
for ti,track in enumerate(self.tracks):
|
||||
track_volume = track.volume * self.master_volume * makeVolume(32.0)
|
||||
if self.n_delay_tracks > 0 and ti == self.n_delay_tracks:
|
||||
self.dataline([-1])
|
||||
self.comment(track.title)
|
||||
params = self.instrparams(
|
||||
self.instruments[track.instr],
|
||||
["bwave","mwave","bdetune","mdetune",
|
||||
"indexspr","index","layers","randomseed",
|
||||
"sustain"] +
|
||||
([int(track_volume.left), int(track_volume.right)]
|
||||
if self.uses_panning else
|
||||
[int(track_volume.left)]) +
|
||||
["bpitchs","mpitchs","bpitchd","mpitchd"] +
|
||||
(["indexd"] if self.uses_indexdecay else []) +
|
||||
(["gain"] if self.uses_gain else []) +
|
||||
["attack","decay","release"])
|
||||
self.dataline(params)
|
||||
|
||||
# List tones and lengths
|
||||
taldata = []
|
||||
prev_t = -1
|
||||
first = True
|
||||
for t,l,v in track.tals:
|
||||
if t > prev_t:
|
||||
if not first:
|
||||
taldata += [0]
|
||||
taldata += [t-prev_t-1]
|
||||
prev_t = t
|
||||
if self.uses_velocity:
|
||||
taldata += [v]
|
||||
taldata += multibyte(l)
|
||||
prev_v = v
|
||||
first = False
|
||||
taldata += [0,-1]
|
||||
self.dataline(taldata)
|
||||
if self.uses_delay:
|
||||
self.dataline([-1,-1])
|
||||
else:
|
||||
self.dataline([-1])
|
||||
|
||||
# Positions of notes
|
||||
self.out += "\n\tsection notepos data align=1\n"
|
||||
self.out += "\n_NotePositions:\n"
|
||||
self.notelist(self.posdata, [])
|
||||
|
||||
# Samples for notes
|
||||
self.out += "\n\tsection notesamp data align=1\n"
|
||||
self.out += "\n_NoteSamples:\n"
|
||||
self.notelist(self.samdata, [-1])
|
||||
|
||||
return self.out
|
||||
|
||||
def makeDeltas(self, init_delta, lines_per_beat):
|
||||
beats_per_line = 1.0/lines_per_beat
|
||||
deltas = []
|
||||
for t in self.tracks:
|
||||
tdeltas = []
|
||||
delta = init_delta
|
||||
note_i = 0
|
||||
for p in range(0, self.length):
|
||||
while t.notes[note_i].line <= p:
|
||||
if not t.notes[note_i].off:
|
||||
delta = p * beats_per_line
|
||||
note_i += 1
|
||||
tdeltas.append(delta)
|
||||
deltas.append(tdeltas)
|
||||
return deltas
|
||||
|
||||
|
||||
def extractTrackNotes(xsong, tr, col):
|
||||
outside_pattern = 0
|
||||
xsequence = xsong.PatternSequence.PatternSequence
|
||||
if not xsequence:
|
||||
xsequence = xsong.PatternSequence.SequenceEntries.SequenceEntry
|
||||
xpatterns = xsong.PatternPool.Patterns.Pattern
|
||||
tname = str(xsong.Tracks.SequencerTrack[tr].Name)
|
||||
|
||||
notes = []
|
||||
|
||||
pattern_top = 0
|
||||
prev_instr = None
|
||||
for posn,xseq in enumerate(xsequence):
|
||||
patn = int(xseq.Pattern)
|
||||
xpat = xpatterns[patn]
|
||||
nlines = int(xpat.NumberOfLines)
|
||||
if tr in [int(xmt) for xmt in xseq.MutedTracks.MutedTrack]:
|
||||
off = Note(pattern_top, posn, patn, "OFF", None, 127)
|
||||
notes.append(off)
|
||||
else:
|
||||
xtrack = xpat.Tracks.PatternTrack[tr]
|
||||
for xline in xtrack.Lines.Line:
|
||||
index = int(xline("index"))
|
||||
if index < nlines:
|
||||
line = pattern_top + index
|
||||
xcol = xline.NoteColumns.NoteColumn[col]
|
||||
if xcol.Note and str(xcol.Note) != "---":
|
||||
instr = str(xcol.Instrument)
|
||||
if instr == "..":
|
||||
if prev_instr is None and str(xcol.Note) != "OFF":
|
||||
raise InputException("Track '%s' pattern %d position %d: Unspecified instrument" % (tname, patn, index))
|
||||
instr = prev_instr
|
||||
prev_instr = instr
|
||||
|
||||
note = Note(line, posn, patn, xcol.Note, instr, xcol.Volume)
|
||||
notes.append(note)
|
||||
|
||||
if note.velocity == 0 or note.velocity > 127:
|
||||
raise InputException("Track '%s' pattern %d position %d: Illegal velocity value" % (tname, patn, index))
|
||||
|
||||
# Check for illegal uses of panning, delay and effect columns
|
||||
def checkColumn(x, msg):
|
||||
if x and not str(x) in ["", "..", "00"]:
|
||||
raise InputException("Track '%s' pattern %d position %d: %s" % (tname, patn, index, msg))
|
||||
checkColumn(xcol.Delay, "Delay column used")
|
||||
for xeff in xline.EffectColumns.EffectColumn.Number:
|
||||
checkColumn(xeff, "Effect column used")
|
||||
else:
|
||||
outside_pattern += 1
|
||||
pattern_top += nlines
|
||||
notes.append(Note(pattern_top, len(xsequence), len(xpatterns), "OFF", 0, 127))
|
||||
|
||||
if outside_pattern > 0:
|
||||
print " * Track '%s': %d note%s outside patterns ignored" % (tname, outside_pattern, "s" * (outside_pattern > 1))
|
||||
|
||||
return notes
|
||||
|
||||
def pickupDelay(xdevices, delay_lengths, delay_strength, tname, ticklength):
|
||||
if isactive(xdevices.DelayDevice):
|
||||
send = float(xdevices.DelayDevice.TrackSend.Value) / 127.0
|
||||
lfeedback = float(xdevices.DelayDevice.LFeedback.Value)
|
||||
rfeedback = float(xdevices.DelayDevice.RFeedback.Value)
|
||||
if float(xdevices.DelayDevice.LineSync.Value):
|
||||
lsynctime = float(xdevices.DelayDevice.LSyncTime.Value)
|
||||
lsyncoffset = float(xdevices.DelayDevice.LSyncOffset.Value)
|
||||
ldelay = (lsynctime + lsyncoffset) * ticklength
|
||||
rsynctime = float(xdevices.DelayDevice.RSyncTime.Value)
|
||||
rsyncoffset = float(xdevices.DelayDevice.RSyncOffset.Value)
|
||||
rdelay = (rsynctime + rsyncoffset) * ticklength
|
||||
else:
|
||||
ldelay = float(xdevices.DelayDevice.LDelay.Value) / 1000.0
|
||||
rdelay = float(xdevices.DelayDevice.RDelay.Value) / 1000.0
|
||||
if abs(lfeedback - send) > 0.05:
|
||||
print " * Track '%s': Left feedback (%0.2f) is different from send value (%0.2f)" % (tname, lfeedback, send)
|
||||
if abs(rfeedback - send) > 0.05:
|
||||
print " * Track '%s': Right feedback (%0.2f) is different from send value (%0.2f)" % (tname, rfeedback, send)
|
||||
if delay_lengths != [0.0, 0.0] and ([ldelay,rdelay] != delay_lengths or send != delay_strength):
|
||||
print " * Track '%s' has different delay parameters from earlier track" % tname
|
||||
return [ldelay,rdelay],send
|
||||
return delay_lengths,delay_strength
|
||||
|
||||
def makeTracks(version, xsong, ticklength):
|
||||
instruments = []
|
||||
delay_tracks = []
|
||||
non_delay_tracks = []
|
||||
delay_lengths = [0.0, 0.0]
|
||||
delay_strength = 0.0
|
||||
|
||||
for ii,xinst in enumerate(xsong.Instruments.Instrument):
|
||||
params = [float(v) for v in instplugins(xinst).PluginDevice.Parameters.Parameter.Value]
|
||||
if params:
|
||||
instrument = Instrument(ii, str(xinst.Name), params)
|
||||
instrument.volume = makeVolume(instplugins(xinst).Volume)
|
||||
instruments.append(instrument)
|
||||
|
||||
else:
|
||||
instruments.append(None)
|
||||
|
||||
for tr,xtrack in enumerate(xsong.Tracks.SequencerTrack):
|
||||
tname = str(xtrack.Name)
|
||||
ncols = int(xtrack.NumberOfVisibleNoteColumns)
|
||||
xdevices = xtrack.FilterDevices.Devices
|
||||
xdevice = xdevices.SequencerTrackDevice
|
||||
if not xdevice:
|
||||
xdevice = xdevices.TrackMixerDevice
|
||||
volume = makeVolume(xdevice.Volume.Value)
|
||||
volume *= makePanning(xdevice.Panning.Value)
|
||||
while isactive(xdevices.SendDevice):
|
||||
if isactive(xdevices.DelayDevice):
|
||||
raise InputException("Track '%s' uses both delay and send" % tname);
|
||||
if str(xdevices.SendDevice.MuteSource) != "true":
|
||||
raise InputException("Track '%s' uses send without Mute Source" % tname);
|
||||
volume *= makeVolume(xdevices.SendDevice.SendAmount.Value)
|
||||
volume *= makePanning(xdevices.SendDevice.SendPan.Value)
|
||||
dest = int(float(xdevices.SendDevice.DestSendTrack.Value))
|
||||
xdevices = xsong.Tracks.SequencerSendTrack[dest].FilterDevices.Devices
|
||||
xdevice = xdevices.SequencerSendTrackDevice
|
||||
if not xdevice:
|
||||
xdevice = xdevices.SendTrackMixerDevice
|
||||
volume *= makeVolume(xdevice.Volume.Value)
|
||||
volume *= makePanning(xdevice.Panning.Value)
|
||||
volume *= makeVolume(xdevice.PostVolume.Value)
|
||||
volume *= makePanning(xdevice.PostPanning.Value)
|
||||
|
||||
for col in range(0,ncols):
|
||||
notes = extractTrackNotes(xsong, tr, col)
|
||||
|
||||
track_instrs = []
|
||||
for note in notes:
|
||||
if not note.off:
|
||||
instr = instruments[note.instr]
|
||||
if instr is None:
|
||||
raise InputException("Track '%s' uses undefined instrument (%d)" % (tname, note.instr));
|
||||
if note.instr not in track_instrs:
|
||||
track_instrs.append(note.instr)
|
||||
|
||||
for instr in track_instrs:
|
||||
track = Track(tr, tname, notes, volume, instr, instruments)
|
||||
if isactive(xdevices.DelayDevice):
|
||||
delay_tracks.append(track)
|
||||
else:
|
||||
non_delay_tracks.append(track)
|
||||
|
||||
delay_lengths,delay_strength = pickupDelay(xdevices, delay_lengths, delay_strength, tname, ticklength)
|
||||
|
||||
for xtrack in xsong.Tracks.SequencerSendTrack:
|
||||
xdevices = xtrack.FilterDevices.Devices
|
||||
if xdevices.DelayDevice:
|
||||
delay_lengths,delay_strength = pickupDelay(xdevices, delay_lengths, delay_strength, tname, ticklength)
|
||||
|
||||
#delay_tracks = sorted(delay_tracks, key = (lambda t : t.instr))
|
||||
#non_delay_tracks = sorted(non_delay_tracks, key = (lambda t : t.instr))
|
||||
|
||||
return (delay_tracks + non_delay_tracks), len(delay_tracks), delay_lengths, delay_strength, instruments
|
||||
|
||||
def makeMusic(xsong):
|
||||
vstnames = set(str(v) for v in instplugins(xsong.Instruments.Instrument).PluginDevice.PluginIdentifier)
|
||||
if len(vstnames) > 1:
|
||||
raise InputException("More than one VST used: %s" % list(vstnames))
|
||||
vstname = list(vstnames)[0]
|
||||
vstmap = { "Clinkster" : 1 }
|
||||
if vstname not in vstmap:
|
||||
raise InputException("Unknown VST used: %s" % vstname)
|
||||
vstversion = vstmap[vstname]
|
||||
print "VST version: %d" % vstversion
|
||||
if vstversion != 1:
|
||||
raise InputException("Only Clinkster version 1 supported")
|
||||
|
||||
xgsd = xsong.GlobalSongData
|
||||
if xgsd.PlaybackEngineVersion and int(xgsd.PlaybackEngineVersion) >= 4:
|
||||
lines_per_minute = float(xgsd.BeatsPerMin) * float(xgsd.LinesPerBeat)
|
||||
print "New timing format: %d ticks per minute" % lines_per_minute
|
||||
else:
|
||||
lines_per_minute = float(xgsd.BeatsPerMin) * 24.0 / float(xgsd.TicksPerLine)
|
||||
print "Old timing format: %d ticks per minute" % lines_per_minute
|
||||
ticklength = 60.0 / lines_per_minute
|
||||
print
|
||||
|
||||
tracks,n_delay_tracks,delay_lengths,delay_strength,instruments = makeTracks(vstversion, xsong, ticklength)
|
||||
|
||||
xpositions = xsong.PatternSequence.PatternSequence.Pattern
|
||||
if not xpositions:
|
||||
xpositions = xsong.PatternSequence.SequenceEntries.SequenceEntry.Pattern
|
||||
xpatterns = xsong.PatternPool.Patterns.Pattern
|
||||
length = 0
|
||||
for xpos in xpositions:
|
||||
patn = int(xpos)
|
||||
xpat = xpatterns[patn]
|
||||
nlines = int(xpat.NumberOfLines)
|
||||
length += nlines
|
||||
|
||||
xmstdev = xsong.Tracks.SequencerMasterTrack.FilterDevices.Devices.SequencerMasterTrackDevice
|
||||
if not xmstdev:
|
||||
xmstdev = xsong.Tracks.SequencerMasterTrack.FilterDevices.Devices.MasterTrackMixerDevice
|
||||
master_volume = makeVolume(xmstdev.Volume.Value)
|
||||
master_volume *= makePanning(xmstdev.Panning.Value)
|
||||
master_volume *= makeVolume(xmstdev.PostVolume.Value)
|
||||
master_volume *= makePanning(xmstdev.PostPanning.Value)
|
||||
|
||||
return Music(vstversion, tracks, instruments, length, ticklength, n_delay_tracks, delay_lengths, delay_strength, master_volume)
|
||||
|
||||
|
||||
def printMusicStats(music):
|
||||
print "Music length: %d ticks at %0.2f ticks per minute" % (music.length, 60.0 / music.ticklength)
|
||||
print
|
||||
for ti,track in enumerate(music.tracks):
|
||||
tnotes = ""
|
||||
for t,l,v in track.tals:
|
||||
num_notes = 0
|
||||
for n in [note for note in track.notes if not note.off and note.instr == track.instr]:
|
||||
if track.notemap[n] == (t,l,v):
|
||||
num_notes += 1
|
||||
if v < 127:
|
||||
tnotes += " %s/%02X:%d(%d)" % (notename(t), v, l, num_notes)
|
||||
else:
|
||||
tnotes += " %s:%d(%d)" % (notename(t), l, num_notes)
|
||||
if music.n_delay_tracks > 0 and ti == 0:
|
||||
print "Tracks with delay:"
|
||||
print
|
||||
if music.n_delay_tracks > 0 and ti == music.n_delay_tracks:
|
||||
print
|
||||
print "Tracks without delay:"
|
||||
print
|
||||
print track.title
|
||||
print tnotes
|
||||
#print "Max: longest %f, total %f" % (music.max_longest_sample, music.max_sample_length_sum)
|
||||
|
||||
def writefile(filename, s):
|
||||
f = open(filename, "wb")
|
||||
f.write(s)
|
||||
f.close()
|
||||
print "Wrote file %s" % filename
|
||||
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print "Usage: %s <input xrns file> <output asm file>" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
infile = sys.argv[1]
|
||||
outfile = sys.argv[2]
|
||||
|
||||
x = XML.makeXML(zipfile.ZipFile(infile).read("Song.xml"))
|
||||
try:
|
||||
music = makeMusic(x.RenoiseSong)
|
||||
print
|
||||
printMusicStats(music)
|
||||
print
|
||||
|
||||
writefile(outfile, music.exportPC(44100.0))
|
||||
|
||||
if len(sys.argv) > 3:
|
||||
deltas = music.makeDeltas(0.0, 1.0)
|
||||
syncfile = sys.argv[3]
|
||||
header = ""
|
||||
header += struct.pack('I', 1)
|
||||
header += struct.pack('I', music.length*4)
|
||||
header += struct.pack('I', len(music.tracks)*music.length*4)
|
||||
body = ""
|
||||
for t,tdeltas in enumerate(deltas):
|
||||
body += struct.pack("%df" % len(tdeltas), *tdeltas)
|
||||
data = header + body
|
||||
writefile(syncfile, data)
|
||||
|
||||
except InputException, e:
|
||||
print "Error in input song: %s" % e.message
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import xml.dom
|
||||
import xml.dom.minidom
|
||||
|
||||
class XML(object):
|
||||
def __init__(self, domlist):
|
||||
self.domlist = list(domlist)
|
||||
|
||||
def __getattr__(self, name):
|
||||
l = []
|
||||
for d in self.domlist:
|
||||
for c in d.childNodes:
|
||||
if c.nodeName == name:
|
||||
l.append(c)
|
||||
return XML(l)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.domlist)
|
||||
|
||||
def __getitem__(self, i):
|
||||
if i >= len(self.domlist):
|
||||
return XML([])
|
||||
return XML([self.domlist[i]])
|
||||
|
||||
def __iter__(self):
|
||||
for d in self.domlist:
|
||||
yield XML([d])
|
||||
|
||||
def __call__(self, attrname):
|
||||
s = ""
|
||||
for d in self.domlist:
|
||||
if d.nodeType == xml.dom.Node.ELEMENT_NODE and d.hasAttribute(attrname):
|
||||
s += d.getAttribute(attrname)
|
||||
return s
|
||||
|
||||
def __str__(self):
|
||||
def collect(dl):
|
||||
s = ""
|
||||
for d in dl:
|
||||
if d.nodeType == xml.dom.Node.TEXT_NODE:
|
||||
s += d.data
|
||||
else:
|
||||
s += collect(d.childNodes)
|
||||
return s
|
||||
return collect(self.domlist)
|
||||
|
||||
def __int__(self):
|
||||
return int(str(self))
|
||||
|
||||
def __float__(self):
|
||||
return float(str(self))
|
||||
|
||||
def __nonzero__(self):
|
||||
return len(self.domlist) != 0
|
||||
|
||||
def replaceText(self, fun):
|
||||
def collect(dl):
|
||||
for d in dl:
|
||||
if d.nodeType == xml.dom.Node.TEXT_NODE:
|
||||
d.data = fun(d.data)
|
||||
else:
|
||||
collect(d.childNodes)
|
||||
collect(self.domlist)
|
||||
|
||||
def setData(self, data):
|
||||
sdata = str(data)
|
||||
for d in self.domlist:
|
||||
for c in d.childNodes:
|
||||
c.data = sdata
|
||||
|
||||
def removeChild(self, child):
|
||||
if len(self.domlist) != len(child.domlist):
|
||||
raise ValueError
|
||||
for p,c in zip(self.domlist, child.domlist):
|
||||
p.removeChild(c)
|
||||
|
||||
def insertBefore(self, newChild, refChild):
|
||||
if len(self.domlist) != len(newChild.domlist) or len(newChild.domlist) != len(refChild.domlist):
|
||||
raise ValueError
|
||||
for p,nc,rc in zip(self.domlist, newChild.domlist, refChild.domlist):
|
||||
p.insertBefore(nc.childNodes[0],rc)
|
||||
|
||||
def export(self):
|
||||
return "".join(x.toxml("utf-8") for x in self.domlist)
|
||||
|
||||
def readXML(filename):
|
||||
return XML([xml.dom.minidom.parse(filename)])
|
||||
|
||||
def makeXML(xstring):
|
||||
return XML([xml.dom.minidom.parseString(xstring)])
|
Binary file not shown.
|
@ -0,0 +1,9 @@
|
|||
del /q temp\*
|
||||
del music.exe
|
||||
|
||||
tools\RenoiseConvert.exe music.xrns temp\music.asm
|
||||
tools\nasmw -f win32 src\clinkster_multithreaded.asm -o temp\clinkster_multithreaded.obj
|
||||
tools\nasmw -f win32 src\play.asm -o temp\play.obj
|
||||
tools\crinkler20\crinkler temp\clinkster_multithreaded.obj temp\play.obj /OUT:music.exe /ENTRY:main tools\kernel32.lib tools\user32.lib tools\winmm.lib tools\msvcrt_old.lib @crinkler_options.txt
|
||||
|
||||
pause
|
|
@ -0,0 +1,9 @@
|
|||
del /q temp\*
|
||||
del music_wav.exe
|
||||
|
||||
tools\RenoiseConvert.exe music.xrns temp\music.asm
|
||||
tools\nasmw -f win32 src\clinkster_multithreaded.asm -o temp\clinkster_multithreaded.obj
|
||||
tools\nasmw -f win32 -dWRITE_WAV src\play.asm -o temp\play.obj
|
||||
tools\crinkler20\crinkler temp\clinkster_multithreaded.obj temp\play.obj /OUT:music_wav.exe /ENTRY:main tools\kernel32.lib tools\user32.lib tools\winmm.lib tools\msvcrt_old.lib @crinkler_options.txt
|
||||
|
||||
pause
|
|
@ -0,0 +1 @@
|
|||
/UNSAFEIMPORT /COMPMODE:INSTANT /HASHSIZE:100
|
|
@ -0,0 +1,4 @@
|
|||
Music composed using 4k synth "Clinkster" by Blueberry / Loonies
|
||||
|
||||
Generating music...
|
||||
|
Binary file not shown.
|
@ -0,0 +1,16 @@
|
|||
|
||||
This setup is for easily building an executable version of a piece of music
|
||||
created using Clinkster.
|
||||
|
||||
Proceed as follows:
|
||||
|
||||
1. Place your music here, named music.xrns.
|
||||
2. Place a text file containing the text you would like the executable to
|
||||
print at startup, named music.txt.
|
||||
3. Optionally modify the Crinkler options in crinkler_options.txt
|
||||
(read the Crinkler manual for details).
|
||||
4. Run build.bat to get an executable that plays the music, or
|
||||
build_wav.bat to get one that writes the music in WAV format to
|
||||
music.wav and then plays it.
|
||||
|
||||
Enjoy!
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
extern Clinkster_GenerateMusic
|
||||
extern Clinkster_StartMusic
|
||||
extern Clinkster_GetPosition
|
||||
extern Clinkster_GetInstrumentTrigger
|
||||
|
||||
extern Clinkster_MusicBuffer
|
||||
extern Clinkster_NoteTiming
|
||||
extern Clinkster_TicksPerSecond
|
||||
extern Clinkster_MusicLength
|
||||
extern Clinkster_NumTracks
|
||||
extern Clinkster_WavFileHeader
|
|
@ -0,0 +1,962 @@
|
|||
|
||||
; If set to 1, timing information is generated during music generation
|
||||
; which is needed for Clinkster_GetInstrumentTrigger.
|
||||
; Set it to 0 if you don't need this functionality.
|
||||
%define CLINKSTER_GENERATE_TIMING_DATA 0
|
||||
|
||||
; Offset applied by Clinkster_GetPosition to compensate for graphics latency.
|
||||
; Measured in samples (44100ths of a second).
|
||||
; The default value of 2048 (corresponding to about 46 milliseconds) is
|
||||
; appropriate for typical display latencies for high-framerate effects.
|
||||
%define CLINKSTER_TIMER_OFFSET 0
|
||||
|
||||
%include "temp/music.asm"
|
||||
|
||||
|
||||
;; ********** Definitions **********
|
||||
|
||||
global Clinkster_GenerateMusic
|
||||
global _Clinkster_GenerateMusic@0
|
||||
global Clinkster_StartMusic
|
||||
global _Clinkster_StartMusic@0
|
||||
global Clinkster_GetPosition
|
||||
global _Clinkster_GetPosition@0
|
||||
global Clinkster_GetInstrumentTrigger
|
||||
global _Clinkster_GetInstrumentTrigger@8
|
||||
|
||||
global Clinkster_MusicBuffer
|
||||
global _Clinkster_MusicBuffer
|
||||
global Clinkster_TicksPerSecond
|
||||
global _Clinkster_TicksPerSecond
|
||||
global Clinkster_MusicLength
|
||||
global _Clinkster_MusicLength
|
||||
global Clinkster_NumTracks
|
||||
global _Clinkster_NumTracks
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
global Clinkster_NoteTiming
|
||||
global _Clinkster_NoteTiming
|
||||
%endif
|
||||
global Clinkster_WavFileHeader
|
||||
global _Clinkster_WavFileHeader
|
||||
|
||||
extern __imp__waveOutOpen@24
|
||||
extern __imp__waveOutPrepareHeader@12
|
||||
extern __imp__waveOutWrite@12
|
||||
extern __imp__waveOutGetPosition@12
|
||||
|
||||
extern __imp__CreateThread@24
|
||||
extern __imp__WaitForSingleObject@8
|
||||
|
||||
%define SAMPLE_RATE 44100
|
||||
%define WAVE_SIZE 65536
|
||||
|
||||
|
||||
;; ********** Public variables **********
|
||||
|
||||
section MusBuf bss align=4
|
||||
Clinkster_MusicBuffer:
|
||||
_Clinkster_MusicBuffer:
|
||||
.align24
|
||||
resw (TOTAL_SAMPLES*2)
|
||||
resw 2 ; padding to catch extra write in conversion
|
||||
|
||||
section tps rdata align=4
|
||||
Clinkster_TicksPerSecond:
|
||||
_Clinkster_TicksPerSecond:
|
||||
dd TICKS_PER_SECOND
|
||||
|
||||
section muslen rdata align=4
|
||||
Clinkster_MusicLength:
|
||||
_Clinkster_MusicLength:
|
||||
dd MUSIC_LENGTH
|
||||
|
||||
section numtr rdata align=4
|
||||
Clinkster_NumTracks:
|
||||
_Clinkster_NumTracks:
|
||||
dd NUMTRACKS
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section musdat bss align=4
|
||||
Clinkster_NoteTiming:
|
||||
_Clinkster_NoteTiming:
|
||||
.align16
|
||||
resd 2*(NUMTRACKS<<LOGNUMTICKS)
|
||||
|
||||
section timing data align=4
|
||||
timing_ptr: dd Clinkster_NoteTiming
|
||||
%endif
|
||||
|
||||
section WavFile rdata align=4
|
||||
Clinkster_WavFileHeader:
|
||||
_Clinkster_WavFileHeader:
|
||||
db "RIFF"
|
||||
dd 36+TOTAL_SAMPLES*4
|
||||
db "WAVE"
|
||||
db "fmt "
|
||||
dd 16
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16
|
||||
db "data"
|
||||
dd TOTAL_SAMPLES*4
|
||||
|
||||
|
||||
;; ********** System structures **********
|
||||
|
||||
section WaveForm rdata align=1
|
||||
_WaveFormat:
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16,0
|
||||
|
||||
section WaveHdr data align=4
|
||||
_WaveHdr:
|
||||
dd Clinkster_MusicBuffer
|
||||
dd (TOTAL_SAMPLES*4)
|
||||
dd 0,0,0,0,0,0
|
||||
|
||||
section wavehand bss align=4
|
||||
_WaveOutHandle:
|
||||
.align16
|
||||
resd 1
|
||||
|
||||
section WaveTime data align=4
|
||||
_WaveTime:
|
||||
dd 4,0,0,0,0,0,0,0
|
||||
|
||||
|
||||
;; ********** Internal buffers **********
|
||||
|
||||
section wforms bss align=4
|
||||
waveforms:
|
||||
.align16
|
||||
resd 6*WAVE_SIZE
|
||||
|
||||
|
||||
;; ********** Instrument parameter access **********
|
||||
|
||||
section paramw rdata align=4
|
||||
param_weights:
|
||||
dd 0.125 ; Release
|
||||
dd 0.125 ; Decay
|
||||
dd 0.125 ; Attack
|
||||
%if USES_GAIN
|
||||
dd 0.125 ; Gain
|
||||
%endif
|
||||
%if USES_INDEXDECAY
|
||||
dd 0.0009765625 ; IndexDecay
|
||||
%endif
|
||||
dd 0.0009765625 ; M PitchDecay
|
||||
dd 0.0009765625 ; B PitchDecay
|
||||
dd 0.083333333333 ; M Pitch
|
||||
dd 0.083333333333 ; B Pitch
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%if USES_PANNING
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%endif
|
||||
dd 0.03125 ; Sustain
|
||||
dd 16307 ; RandomSeed
|
||||
dd 1 ; Layers
|
||||
dd 4096.0 ; Index
|
||||
dd 0.125 ; Index Spread
|
||||
dd 0.0009765625 ; M Detune
|
||||
dd 0.0009765625 ; B Detune
|
||||
dd 65536 ; ModWave
|
||||
dd 65536 ; BaseWave
|
||||
|
||||
struc instr_params
|
||||
ip_basewave: resd 1
|
||||
ip_modwave: resd 1
|
||||
ip_bdetune: resd 1
|
||||
ip_mdetune: resd 1
|
||||
ip_indexspr: resd 1
|
||||
ip_index: resd 1
|
||||
ip_layers: resd 1
|
||||
ip_randomseed: resd 1
|
||||
ip_sustain: resd 1
|
||||
ip_volume: resd 1+USES_PANNING
|
||||
ip_bpitch: resd 1
|
||||
ip_mpitch: resd 1
|
||||
ip_bpitchd: resd 1
|
||||
ip_mpitchd: resd 1
|
||||
%if USES_INDEXDECAY
|
||||
ip_indexd: resd 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
ip_gain: resd 1
|
||||
%endif
|
||||
ip_attack: resd 1
|
||||
ip_decay: resd 1
|
||||
ip_release: resd 1
|
||||
endstruc
|
||||
|
||||
%define ip_INT 0
|
||||
%define ip_FLOAT 0
|
||||
%define IP(f,t) dword [dword ebx + g_instrparams + ip_ %+ f + ip_ %+ t]
|
||||
%define IPI(f,i,t) dword [dword ebx + g_instrparams + ip_ %+ f + ip_ %+ t + i]
|
||||
|
||||
|
||||
;; ********** Internal constants and tables **********
|
||||
|
||||
section resamp rdata align=4
|
||||
resamplefilter:
|
||||
db -1,-2,-4,-4,-2,3,14,30,51,98,116,126
|
||||
db 126,116,98,51,30,14,3,-2,-4,-4,-2,-1
|
||||
resamplefilter_end:
|
||||
FILTER_SIZE equ (resamplefilter_end-resamplefilter)
|
||||
|
||||
section wavestep rdata align=4
|
||||
c_wavestep: dd 0.000030517578125
|
||||
section basefreq rdata align=4
|
||||
c_basefreq: dd 2.86698696365342
|
||||
section halfnote rdata align=4
|
||||
c_halfnote: dd 1.05946309435929
|
||||
section finalamp rdata align=4
|
||||
c_finalamp: dd 32767
|
||||
section velfac rdata align=4
|
||||
c_velocityfac: dd 0.007874015748031496
|
||||
section delaystr rdata align=4
|
||||
c_delaystr: dd DELAY_STRENGTH
|
||||
section offset rdata align=4
|
||||
c_timeoffset: dd CLINKSTER_TIMER_OFFSET*4
|
||||
section tempo rdata align=4
|
||||
c_ticklength: dd SUBSAMPLES_PER_TICK/4*4
|
||||
section half rdata align=4
|
||||
c_onehalf: dd 0.5
|
||||
|
||||
|
||||
;; ********** Internal global variables **********
|
||||
|
||||
struc globalvars
|
||||
g_phasetemp: resd 1
|
||||
g_layer_random: resd 1
|
||||
g_stereo: resd 1 ; 0 for left channel, 2 for right channel
|
||||
g_noteposptr: resd 1
|
||||
g_notesamptr: resd 1
|
||||
g_instrparams: resb instr_params_size
|
||||
g_layerparams: resq 0
|
||||
g_layer_bfreq: resq 1
|
||||
g_layer_mfreq: resq 1
|
||||
g_layer_index: resq 1
|
||||
g_layer_bpitch: resq 1
|
||||
g_layer_mpitch: resq 1
|
||||
g_layer_bpitchd: resq 1
|
||||
g_layer_mpitchd: resq 1
|
||||
%if USES_INDEXDECAY
|
||||
g_layer_indexd: resq 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
g_layer_gain: resq 1
|
||||
%endif
|
||||
g_layer_attack: resq 1
|
||||
g_layer_decay: resq 1
|
||||
g_layer_release: resq 1
|
||||
|
||||
alignb 256
|
||||
g_InstrumentPointers:
|
||||
resd MAX_TRACK_INSTRUMENT_RENDERS+1
|
||||
|
||||
resd MAX_DELAY_LENGTH
|
||||
alignb 16777216
|
||||
g_MixingBuffer:
|
||||
resd TOTAL_SAMPLES
|
||||
|
||||
alignb 16777216
|
||||
g_InstrumentBuffer:
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
resd 256
|
||||
alignb 16777216
|
||||
g_InstrumentRender:
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
alignb 16777216
|
||||
g_InstrumentStore:
|
||||
resd MAX_TOTAL_INSTRUMENT_SAMPLES
|
||||
|
||||
endstruc
|
||||
|
||||
section vars bss align=8
|
||||
vars_align16
|
||||
globals:
|
||||
resb globalvars_size
|
||||
resb globalvars_size
|
||||
|
||||
|
||||
;; ********** Generate the sound for one layer **********
|
||||
|
||||
section mklayer text align=1
|
||||
makelayer:
|
||||
lea edx, [dword ebx + g_layerparams]
|
||||
|
||||
; Init random variables for layer
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fld IP(bdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fld IP(mdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fmul IP(indexspr, FLOAT)
|
||||
fadd IP(index, FLOAT)
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
; Init exponentiated variables for layer
|
||||
lea edi, [dword ebx + g_instrparams+ip_bpitch]
|
||||
mov ecx, 7+USES_INDEXDECAY+USES_GAIN
|
||||
.powloop:
|
||||
fld dword [edi]
|
||||
|
||||
fld1
|
||||
fld st1
|
||||
fprem
|
||||
fstp st1
|
||||
f2xm1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fscale
|
||||
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
fstp st0
|
||||
scasd
|
||||
loop .powloop
|
||||
|
||||
; Loop over samples
|
||||
fldz ; b phase
|
||||
fldz ; m phase
|
||||
lea edi, [dword ebx + g_InstrumentBuffer]
|
||||
|
||||
; Calculate max note size
|
||||
xor eax, eax
|
||||
%if USES_VELOCITY
|
||||
lodsb ; Skip velocity
|
||||
%endif
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; Length of longest note with this tone
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
add eax, MAX_RELEASE_SUBSAMPLES
|
||||
xchg ecx, eax
|
||||
|
||||
.sampleloop:
|
||||
lea edx, [dword ebx + g_layerparams]
|
||||
|
||||
; Look up and normalize mod wave
|
||||
fist dword [ebx]
|
||||
mov eax, IP(modwave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Adjust by index
|
||||
fmul qword [edx + 2*8] ; layer_index
|
||||
fadd st0, st2
|
||||
|
||||
; Look up base wave
|
||||
fistp dword [ebx]
|
||||
mov eax, IP(basewave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Update phases
|
||||
fld qword [edx] ; layer_bfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_bpitch
|
||||
faddp st3, st0
|
||||
|
||||
fld qword [edx] ; layer_mfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_mpitch
|
||||
faddp st2, st0
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fld qword [edx] ; layer_index
|
||||
fld1
|
||||
fadd st1, st0
|
||||
fsubp st1, st0
|
||||
%endif
|
||||
add edx, byte 8
|
||||
|
||||
; Update pitches: p := (p-1)*d+1
|
||||
.update:
|
||||
fld1
|
||||
fld qword [edx] ; layer_(b/m)pitch
|
||||
fsub st0, st1
|
||||
fmul qword [edx + 2*8] ; layer_(b/m)pitchd
|
||||
faddp st1, st0
|
||||
fstp qword [edx] ; layer_(b/m)pitch
|
||||
add edx, byte 8
|
||||
|
||||
neg ecx
|
||||
js .update
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fmul qword [edx + 2*8] ; layer_indexd
|
||||
fstp qword [edx - 3*8] ; layer_index
|
||||
%endif
|
||||
|
||||
; Add to existing layers
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
|
||||
loop .sampleloop
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Interpolate one section of amplitude envelope **********
|
||||
|
||||
section adsr text align=1
|
||||
apply_adsr:
|
||||
; On condition g:
|
||||
; st0 = amplitude target
|
||||
; st1 = amplitude
|
||||
; st2 = velocity / nlayers
|
||||
; eax = number of samples
|
||||
; ecx = sample index
|
||||
; On condition le:
|
||||
; st0 = number of samples
|
||||
; st1 = amplitude target
|
||||
; st2 = amplitude
|
||||
; st3 = velocity / nlayers
|
||||
; ecx = sample index
|
||||
|
||||
push eax
|
||||
jg .integer_length
|
||||
fimul dword [c_finalamp]
|
||||
fistp dword [esp]
|
||||
.integer_length:
|
||||
fsub st0, st1
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
add eax, ecx
|
||||
fdivp st1, st0
|
||||
|
||||
.adsrloop:
|
||||
fld dword [dword ebx + g_InstrumentBuffer + ecx*4]
|
||||
fmul st0, st3 ; velocity / nlayers
|
||||
fmul st0, st2 ; envelope value
|
||||
|
||||
%if USES_GAIN
|
||||
fld1
|
||||
fsubr qword [dword ebx + g_layer_gain]
|
||||
fmul st0, st1
|
||||
fmul st0, st1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fdivr qword [dword ebx + g_layer_gain]
|
||||
fsqrt
|
||||
fmulp st1, st0
|
||||
%endif
|
||||
|
||||
fstp dword [dword ebx + g_InstrumentRender + ecx*4]
|
||||
|
||||
fadd st1, st0
|
||||
inc ecx
|
||||
|
||||
cmp ecx, eax
|
||||
jl .adsrloop
|
||||
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Main music generation **********
|
||||
|
||||
section genMus text align=1
|
||||
Clinkster_GenerateMusic:
|
||||
_Clinkster_GenerateMusic@0:
|
||||
pusha
|
||||
fninit
|
||||
|
||||
; Make waveforms
|
||||
mov edi, waveforms
|
||||
%if USES_SINE
|
||||
fldz
|
||||
mov ecx, WAVE_SIZE
|
||||
.sineloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .sineloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SAWTOOTH
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.sawtoothloop:
|
||||
fadd dword [c_wavestep]
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .sawtoothloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SQUARE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.squareloop:
|
||||
cmp ecx, WAVE_SIZE/2
|
||||
jne .notflipsq
|
||||
fabs
|
||||
.notflipsq:
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .squareloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_PARABOLA
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.parabolaloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fmul st0, st1
|
||||
fadd st0, st0
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .parabolaloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_TRIANGLE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.triangleloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fadd st0, st1
|
||||
fabs
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .triangleloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_NOISE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.noiseloop:
|
||||
fadd dword [c_wavestep]
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .noiseloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
push byte 0 ; lpThreadId
|
||||
push byte 0 ; dwCreationFlags
|
||||
push byte 0 ; lpParameter
|
||||
push makechannel
|
||||
push byte 0 ; dwStackSize
|
||||
push byte 0 ; lpThreadAttributes
|
||||
call [__imp__CreateThread@24]
|
||||
|
||||
push byte -1
|
||||
push eax
|
||||
|
||||
push byte 2
|
||||
call makechannel
|
||||
|
||||
call [__imp__WaitForSingleObject@8]
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
makechannel:
|
||||
; eax = channel (0 or 2)
|
||||
mov eax, [esp + 4]
|
||||
mov edx, globalvars_size/2
|
||||
mul edx
|
||||
mov ebx, globals
|
||||
add ebx, eax
|
||||
mov eax, [esp + 4]
|
||||
mov [dword ebx + g_stereo], eax
|
||||
|
||||
mov dword [dword ebx + g_noteposptr], _NotePositions
|
||||
mov dword [dword ebx + g_notesamptr], _NoteSamples
|
||||
|
||||
mov esi, _InstrumentData
|
||||
%if USES_DELAY
|
||||
jmp short .trackloop
|
||||
|
||||
.delay:
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
mov edx, (LEFT_DELAY_LENGTH-RIGHT_DELAY_LENGTH)*4/2
|
||||
mul edx
|
||||
sub eax, LEFT_DELAY_LENGTH*4
|
||||
lea edi, [dword ebx + g_MixingBuffer]
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
.delayloop:
|
||||
fld dword [edi+eax]
|
||||
fmul dword [c_delaystr]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .delayloop
|
||||
%endif
|
||||
|
||||
.trackloop:
|
||||
; ESI = instr data
|
||||
lea edi, [dword ebx + g_instrparams]
|
||||
mov ecx, instr_params_size/4
|
||||
.ploop:
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [param_weights-4+ecx*4]
|
||||
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .ploop
|
||||
|
||||
lea edi, [dword ebx + g_instrparams+ip_bpitchd]
|
||||
mov ecx, 2+USES_INDEXDECAY
|
||||
.cubeloop:
|
||||
fld dword [edi]
|
||||
fld st0
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .cubeloop
|
||||
|
||||
lea ebp, [dword ebx + g_InstrumentPointers]
|
||||
lea edi, [dword ebx + g_InstrumentStore]
|
||||
mov dword [ebp], edi ; store first instrument instance address
|
||||
fld dword [c_basefreq]
|
||||
|
||||
; Loop over instrument tones
|
||||
.toneloop:
|
||||
xor eax, eax
|
||||
lodsb ; Tone
|
||||
.freqloop:
|
||||
fmul dword [c_halfnote]
|
||||
dec eax
|
||||
jge .freqloop
|
||||
|
||||
; random seed for channel = RandomSeed * 16307 + channel * 12042
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
mov edx, 12042/2
|
||||
mul edx
|
||||
add eax, IP(randomseed,INT)
|
||||
xchg ecx, eax
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
xor eax, eax
|
||||
lea edi, [dword ebx + g_InstrumentBuffer]
|
||||
mov ecx, MAX_INSTRUMENT_SUBSAMPLES
|
||||
rep stosd
|
||||
|
||||
; Loop over layers
|
||||
mov ecx, IP(layers,INT)
|
||||
.layerloop:
|
||||
pusha
|
||||
|
||||
call makelayer
|
||||
|
||||
popa
|
||||
loop .layerloop
|
||||
|
||||
.lengthloop:
|
||||
%if USES_VELOCITY
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [c_velocityfac]
|
||||
%else
|
||||
fld1
|
||||
%endif
|
||||
fidiv IP(layers,INT)
|
||||
|
||||
xor ecx, ecx ; sample index
|
||||
fldz ; amplitude level
|
||||
|
||||
fld1 ; attack amplitude target
|
||||
fld qword [dword ebx + g_layer_attack]; attack length
|
||||
call apply_adsr
|
||||
|
||||
fld IP(sustain,FLOAT) ; decay amplitude target
|
||||
fld qword [dword ebx + g_layer_decay] ; decay length
|
||||
call apply_adsr
|
||||
|
||||
xor eax, eax
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; note length in ticks
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
sub eax, ecx ; note length exclusing attack and decay
|
||||
jle .nosustain ; attack + decay overflows note length
|
||||
fld IP(sustain,FLOAT) ; sustain amplitude target
|
||||
call apply_adsr
|
||||
.nosustain:
|
||||
|
||||
fldz ; release amplitude target
|
||||
fld qword [dword ebx + g_layer_release];release length
|
||||
call apply_adsr
|
||||
|
||||
fldz ; padding amplitude
|
||||
fld1 ; padding length
|
||||
call apply_adsr
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
|
||||
; Resampling
|
||||
push esi
|
||||
mov edi, [ebp] ; instrument instance address
|
||||
add ebp, byte 4
|
||||
|
||||
xchg edx, eax
|
||||
lea esi, [dword ebx + g_InstrumentRender - FILTER_SIZE*4]
|
||||
.resampleloop:
|
||||
fldz
|
||||
mov ecx, FILTER_SIZE
|
||||
.filterloop:
|
||||
movsx eax, byte [resamplefilter + ecx - 1]
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [esi + ecx*4]
|
||||
faddp st1, st0
|
||||
loop .filterloop
|
||||
|
||||
%if USES_PANNING
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
fmul IPI(volume,eax*2,FLOAT)
|
||||
%else
|
||||
fmul IP(volume,FLOAT)
|
||||
%endif
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add esi, byte 4*4
|
||||
|
||||
sub edx, byte 4
|
||||
jg .resampleloop
|
||||
|
||||
mov [ebp], edi ; store instrument instance address
|
||||
pop esi
|
||||
|
||||
cmp [esi], byte 0
|
||||
jne near .lengthloop
|
||||
lodsb
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .toneloop
|
||||
lodsb
|
||||
fstp st0
|
||||
|
||||
; Mixing
|
||||
lea ebp, [dword ebx + g_MixingBuffer]
|
||||
xchg esi, dword [dword ebx + g_notesamptr]
|
||||
.noteloop:
|
||||
xchg esi, dword [dword ebx + g_noteposptr]
|
||||
xor eax, eax
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notepos
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notepos:
|
||||
lodsb
|
||||
mov edx, SUBSAMPLES_PER_TICK/4*4
|
||||
mul edx
|
||||
add ebp, eax
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, SUBSAMPLES_PER_TICK/4*4
|
||||
div ecx
|
||||
xchg edx, eax
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
mov ecx, edx
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
add eax, edx
|
||||
stosd
|
||||
%endif
|
||||
|
||||
xchg esi, dword [dword ebx + g_noteposptr]
|
||||
xor eax, eax
|
||||
lodsb
|
||||
mov edx, dword [dword ebx + g_InstrumentPointers + eax*4] ; Instrument instance ptr
|
||||
mov edi, ebp
|
||||
|
||||
.mixloop:
|
||||
fld dword [edx]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add edx, byte 4
|
||||
|
||||
cmp edx, dword [dword ebx + g_InstrumentPointers + eax*4 + 4]
|
||||
jl .mixloop
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .noteloop
|
||||
lodsb
|
||||
xchg esi, dword [dword ebx + g_notesamptr]
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, 1<<LOGNUMTICKS
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
sub ecx, eax
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
%endif
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .trackloop
|
||||
lodsb
|
||||
|
||||
%if USES_DELAY
|
||||
cmp [esi], byte 0
|
||||
jge near .delay
|
||||
%endif
|
||||
|
||||
; Clamp and convert to shorts
|
||||
fld1
|
||||
mov edi, Clinkster_MusicBuffer
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
add edi, dword [dword ebx + g_stereo]
|
||||
.sloop:
|
||||
fld dword [dword ebx + g_MixingBuffer + ecx*4]
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
|
||||
fimul dword [c_finalamp]
|
||||
fistp word [edi + ecx*4]
|
||||
loop .sloop
|
||||
fstp st0
|
||||
ret 4
|
||||
|
||||
|
||||
;; ********** Start music **********
|
||||
|
||||
section startmus text align=1
|
||||
Clinkster_StartMusic:
|
||||
_Clinkster_StartMusic@0:
|
||||
; Start music
|
||||
push byte 0
|
||||
push byte 0
|
||||
push byte 0
|
||||
push _WaveFormat
|
||||
push byte -1
|
||||
push _WaveOutHandle
|
||||
call [__imp__waveOutOpen@24]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle] ; waveOutHandle
|
||||
call [__imp__waveOutPrepareHeader@12]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutWrite@12]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get current play position **********
|
||||
|
||||
section getpos text align=1
|
||||
Clinkster_GetPosition:
|
||||
_Clinkster_GetPosition@0:
|
||||
push byte 32 ; sizeof(MMTIME)
|
||||
push _WaveTime
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutGetPosition@12]
|
||||
|
||||
fild dword [_WaveTime+4]
|
||||
%if CLINKSTER_TIMER_OFFSET>0
|
||||
fiadd dword [c_timeoffset]
|
||||
%endif
|
||||
fidiv dword [c_ticklength]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get time since instrument trigger **********
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section insttrig text align=1
|
||||
Clinkster_GetInstrumentTrigger:
|
||||
_Clinkster_GetInstrumentTrigger@8:
|
||||
cvttss2si eax, [esp+8]
|
||||
mov ecx, [esp+4]
|
||||
shl ecx, LOGNUMTICKS+2
|
||||
fld dword [esp+8]
|
||||
fisub dword [Clinkster_NoteTiming+ecx+eax*4]
|
||||
ret 8
|
||||
%endif
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
%include "src/clinkster.inc"
|
||||
|
||||
global _main
|
||||
|
||||
extern __imp__fopen
|
||||
extern __imp__fwrite
|
||||
extern __imp__fclose
|
||||
extern __imp__printf
|
||||
extern __imp__GetAsyncKeyState@4
|
||||
extern __imp__ExitProcess@4
|
||||
extern __imp__Sleep@4
|
||||
|
||||
section main text align=1
|
||||
|
||||
_main:
|
||||
push message
|
||||
push messageformat
|
||||
call [__imp__printf]
|
||||
add esp, byte 2*4
|
||||
|
||||
call Clinkster_GenerateMusic
|
||||
|
||||
%ifdef WRITE_WAV
|
||||
push wavname
|
||||
push wavformat
|
||||
call [__imp__printf]
|
||||
add esp, byte 2*4
|
||||
|
||||
push filemode
|
||||
push wavname
|
||||
call [__imp__fopen]
|
||||
add esp, byte 2*4
|
||||
|
||||
push eax
|
||||
push eax
|
||||
push eax
|
||||
push byte 44
|
||||
push byte 1
|
||||
push Clinkster_WavFileHeader
|
||||
call [__imp__fwrite]
|
||||
add esp, byte 3*4
|
||||
|
||||
push dword [Clinkster_WavFileHeader+40]
|
||||
push byte 1
|
||||
push Clinkster_MusicBuffer
|
||||
call [__imp__fwrite]
|
||||
add esp, byte 3*4
|
||||
|
||||
call [__imp__fclose]
|
||||
add esp, byte 1*4
|
||||
%endif
|
||||
|
||||
call Clinkster_StartMusic
|
||||
|
||||
.playloop:
|
||||
mov ebx, 60
|
||||
|
||||
fild dword [Clinkster_MusicLength]
|
||||
fdiv dword [Clinkster_TicksPerSecond]
|
||||
push eax
|
||||
fistp dword [esp]
|
||||
pop eax ; music length in seconds
|
||||
|
||||
xor edx, edx
|
||||
div ebx
|
||||
push edx
|
||||
push eax
|
||||
|
||||
call Clinkster_GetPosition
|
||||
fdiv dword [Clinkster_TicksPerSecond]
|
||||
push eax
|
||||
fistp dword [esp]
|
||||
pop eax ; play position in seconds
|
||||
|
||||
xor edx, edx
|
||||
div ebx
|
||||
push edx
|
||||
push eax
|
||||
|
||||
push timeformat
|
||||
call [__imp__printf]
|
||||
add esp, byte 5*4
|
||||
|
||||
push byte 100
|
||||
call [__imp__Sleep@4]
|
||||
|
||||
push byte 27
|
||||
call [__imp__GetAsyncKeyState@4]
|
||||
test ax, ax
|
||||
je .playloop
|
||||
|
||||
push byte 0
|
||||
call [__imp__ExitProcess@4]
|
||||
|
||||
section mformat rdata align=1
|
||||
|
||||
messageformat:
|
||||
db "%s",0
|
||||
|
||||
section wformat rdata align=1
|
||||
|
||||
wavformat:
|
||||
db "Writing music to %s...",10,10,0
|
||||
|
||||
section wname rdata align=1
|
||||
|
||||
wavname:
|
||||
db "music.wav",0
|
||||
|
||||
section wb rdata align=1
|
||||
filemode:
|
||||
db "wb",0
|
||||
|
||||
section tformat rdata align=1
|
||||
|
||||
timeformat:
|
||||
db 13,"Playing %d:%02d / %d:%02d",0
|
||||
|
||||
section message rdata align=1
|
||||
|
||||
message:
|
||||
incbin "music.txt"
|
||||
db 0
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
|
||||
Change history of Clinkster:
|
||||
|
||||
2016-04-15:
|
||||
- Fixed an error in the multithreaded player code which made it not
|
||||
compile if panning was used.
|
||||
- Added a WAV writer feature to the easy_exe setup.
|
||||
- Added checks for illegal use of command columns to the converter.
|
||||
- Added music from U-Boat to examples.
|
||||
|
||||
2015-10-31:
|
||||
- Added some code in the player to avoid denormals in the index decay,
|
||||
speeding up computation of long notes with high index decay.
|
||||
- Padded the music buffer to avoid writing into adjacent memory.
|
||||
- Included a multithreaded version of the player, which computes the
|
||||
left and right channels in separate threads.
|
||||
- Included a Windows 64-bit build of the VST.
|
||||
|
||||
2014-11-30:
|
||||
- Added converter support for Renoise 3
|
||||
- Added some checks in the converter for illegal use of the
|
||||
volume, panning, delay and effect columns
|
||||
|
||||
2013-08-18:
|
||||
- Added music from Wishful Twisting to examples
|
||||
|
||||
2013-08-15:
|
||||
- Fixed bug in converter: sometimes incorrect waveforms would be assigned
|
||||
to instruments used in more than one track
|
||||
- Fixed bug in converter: music would break if attack, decay or release
|
||||
was set to -128 (minimum)
|
||||
- Fixed bug in player: crash if sine waveform not used
|
||||
- One more example song
|
||||
- A bunch of additional example instruments
|
||||
|
||||
2013-07-19: First public release
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
CLINKSTER - a software synthesizer for 4k intros by Blueberry / Loonies
|
||||
|
||||
|
||||
With the exceptions noted below, all content of this package is Copyright
|
||||
2008-2016 Aske Simon Christensen. It may be freely used, distributed,
|
||||
modified, redistributed, studied and laughed at by any person or entity.
|
||||
|
||||
ALL CONTENT OF THE PACKAGE COMES WITH NO WARRANTY OF ANY KIND. THE AUTHORS OF
|
||||
THE CONTENT CAN NOT BE HELD RESPONSIBLE FOR ANY CONSEQUENCES OF THE USE OF THE
|
||||
CONTENT, EVEN IF YOUR CAPS-LOCK KEY IS STUCK.
|
||||
|
||||
If you distribute music made using the synth, on its own or as part of a
|
||||
composite work, proper attribution is highly appreciated, though not strictly
|
||||
required.
|
||||
|
||||
|
||||
Exceptions:
|
||||
|
||||
- The music examples in examples/songs are Copyright of their respective
|
||||
authors. They are distributable under the Creative Commons Attribution
|
||||
license.
|
||||
|
||||
- The VST is based on the VST SDK, located in vst_src/source/vst2.x, which is
|
||||
Copyright Steinberg Media Technologies Gmbh.
|
||||
|
||||
- Crinkler, located in easy_exe/tools/crinkler20, is covered by its own
|
||||
licensing terms, which are included.
|
||||
|
||||
- The .lib and .dll files in easy_exe/tools are Copyright Microsoft
|
||||
Corporation.
|
||||
|
||||
- Nasm, located in easy_exe/tools, is distributable under the GNU Lesser
|
||||
General Public License.
|
|
@ -0,0 +1,46 @@
|
|||
#include "clinkster.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
|
||||
void printTime(float ticks) {
|
||||
int sec = (int)(ticks / Clinkster_TicksPerSecond);
|
||||
printf("%d:%02d", sec / 60, sec % 60);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Music composed using 4k synth \"Clinkster\" by Blueberry / Loonies\n\n");
|
||||
|
||||
printf("Generating...\n");
|
||||
Clinkster_GenerateMusic();
|
||||
|
||||
printf("Saving...\n");
|
||||
FILE *outfile = fopen("music.wav", "wb");
|
||||
fwrite(Clinkster_WavFileHeader, 1, sizeof(Clinkster_WavFileHeader), outfile);
|
||||
fwrite(Clinkster_MusicBuffer, 1, Clinkster_WavFileHeader[10], outfile);
|
||||
fclose(outfile);
|
||||
|
||||
printf("Playing...\n\n");
|
||||
Clinkster_StartMusic();
|
||||
while (!GetAsyncKeyState(VK_ESCAPE)) {
|
||||
float pos = Clinkster_GetPosition();
|
||||
if (pos > Clinkster_MusicLength) break;
|
||||
printf("\r ");
|
||||
printTime(pos);
|
||||
printf(" / ");
|
||||
printTime((float)Clinkster_MusicLength);
|
||||
|
||||
printf(" ");
|
||||
for (int i = 0 ; i < Clinkster_NumTracks ; i++) {
|
||||
float t = Clinkster_GetInstrumentTrigger(i, pos);
|
||||
int ti = (int)(t * 0.25);
|
||||
if (ti > 3) ti = 3;
|
||||
printf("%c", "|:. "[ti]);
|
||||
}
|
||||
|
||||
Sleep(100);
|
||||
}
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,947 @@
|
|||
|
||||
; If set to 1, timing information is generated during music generation
|
||||
; which is needed for Clinkster_GetInstrumentTrigger.
|
||||
; Set it to 0 if you don't need this functionality.
|
||||
%define CLINKSTER_GENERATE_TIMING_DATA 0
|
||||
|
||||
; Offset applied by Clinkster_GetPosition to compensate for graphics latency.
|
||||
; Measured in samples (44100ths of a second).
|
||||
; The default value of 2048 (corresponding to about 46 milliseconds) is
|
||||
; appropriate for typical display latencies for high-framerate effects.
|
||||
%define CLINKSTER_TIMER_OFFSET 2048
|
||||
|
||||
%include "music.asm"
|
||||
|
||||
|
||||
;; ********** Definitions **********
|
||||
|
||||
global Clinkster_GenerateMusic
|
||||
global _Clinkster_GenerateMusic@0
|
||||
global Clinkster_StartMusic
|
||||
global _Clinkster_StartMusic@0
|
||||
global Clinkster_GetPosition
|
||||
global _Clinkster_GetPosition@0
|
||||
global Clinkster_GetInstrumentTrigger
|
||||
global _Clinkster_GetInstrumentTrigger@8
|
||||
|
||||
global Clinkster_MusicBuffer
|
||||
global _Clinkster_MusicBuffer
|
||||
global Clinkster_TicksPerSecond
|
||||
global _Clinkster_TicksPerSecond
|
||||
global Clinkster_MusicLength
|
||||
global _Clinkster_MusicLength
|
||||
global Clinkster_NumTracks
|
||||
global _Clinkster_NumTracks
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
global Clinkster_NoteTiming
|
||||
global _Clinkster_NoteTiming
|
||||
%endif
|
||||
global Clinkster_WavFileHeader
|
||||
global _Clinkster_WavFileHeader
|
||||
|
||||
extern __imp__waveOutOpen@24
|
||||
extern __imp__waveOutPrepareHeader@12
|
||||
extern __imp__waveOutWrite@12
|
||||
extern __imp__waveOutGetPosition@12
|
||||
|
||||
%define SAMPLE_RATE 44100
|
||||
%define WAVE_SIZE 65536
|
||||
|
||||
|
||||
;; ********** Public variables **********
|
||||
|
||||
section MusBuf bss align=4
|
||||
Clinkster_MusicBuffer:
|
||||
_Clinkster_MusicBuffer:
|
||||
.align24
|
||||
resw (TOTAL_SAMPLES*2)
|
||||
resw 2 ; padding to catch extra write in conversion
|
||||
|
||||
section tps rdata align=4
|
||||
Clinkster_TicksPerSecond:
|
||||
_Clinkster_TicksPerSecond:
|
||||
dd TICKS_PER_SECOND
|
||||
|
||||
section muslen rdata align=4
|
||||
Clinkster_MusicLength:
|
||||
_Clinkster_MusicLength:
|
||||
dd MUSIC_LENGTH
|
||||
|
||||
section numtr rdata align=4
|
||||
Clinkster_NumTracks:
|
||||
_Clinkster_NumTracks:
|
||||
dd NUMTRACKS
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section musdat bss align=4
|
||||
Clinkster_NoteTiming:
|
||||
_Clinkster_NoteTiming:
|
||||
.align16
|
||||
resd 2*(NUMTRACKS<<LOGNUMTICKS)
|
||||
|
||||
section timing data align=4
|
||||
timing_ptr: dd Clinkster_NoteTiming
|
||||
%endif
|
||||
|
||||
section WavFile rdata align=4
|
||||
Clinkster_WavFileHeader:
|
||||
_Clinkster_WavFileHeader:
|
||||
db "RIFF"
|
||||
dd 36+TOTAL_SAMPLES*4
|
||||
db "WAVE"
|
||||
db "fmt "
|
||||
dd 16
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16
|
||||
db "data"
|
||||
dd TOTAL_SAMPLES*4
|
||||
|
||||
|
||||
;; ********** System structures **********
|
||||
|
||||
section WaveForm rdata align=1
|
||||
_WaveFormat:
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16,0
|
||||
|
||||
section WaveHdr data align=4
|
||||
_WaveHdr:
|
||||
dd Clinkster_MusicBuffer
|
||||
dd (TOTAL_SAMPLES*4)
|
||||
dd 0,0,0,0,0,0
|
||||
|
||||
section wavehand bss align=4
|
||||
_WaveOutHandle:
|
||||
.align16
|
||||
resd 1
|
||||
|
||||
section WaveTime data align=4
|
||||
_WaveTime:
|
||||
dd 4,0,0,0,0,0,0,0
|
||||
|
||||
|
||||
;; ********** Internal buffers **********
|
||||
|
||||
section MixBuf bss align=4
|
||||
resd MAX_DELAY_LENGTH
|
||||
_MixingBuffer:
|
||||
.align24
|
||||
resd TOTAL_SAMPLES
|
||||
|
||||
section InstrBuf bss align=4
|
||||
_InstrumentBuffer:
|
||||
.align16
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
section InstrRen bss align=4
|
||||
resd 256
|
||||
_InstrumentRender:
|
||||
.align16
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
section InstrSto bss align=4
|
||||
_InstrumentStore:
|
||||
.align16
|
||||
resd MAX_TOTAL_INSTRUMENT_SAMPLES
|
||||
|
||||
section InstrPoi bss align=4
|
||||
_InstrumentPointers:
|
||||
.align16
|
||||
resd MAX_TRACK_INSTRUMENT_RENDERS+1
|
||||
|
||||
section wforms bss align=4
|
||||
waveforms:
|
||||
.align16
|
||||
resd 6*WAVE_SIZE
|
||||
|
||||
|
||||
;; ********** Instrument parameter access **********
|
||||
|
||||
section paramw rdata align=4
|
||||
param_weights:
|
||||
dd 0.125 ; Release
|
||||
dd 0.125 ; Decay
|
||||
dd 0.125 ; Attack
|
||||
%if USES_GAIN
|
||||
dd 0.125 ; Gain
|
||||
%endif
|
||||
%if USES_INDEXDECAY
|
||||
dd 0.0009765625 ; IndexDecay
|
||||
%endif
|
||||
dd 0.0009765625 ; M PitchDecay
|
||||
dd 0.0009765625 ; B PitchDecay
|
||||
dd 0.083333333333 ; M Pitch
|
||||
dd 0.083333333333 ; B Pitch
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%if USES_PANNING
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%endif
|
||||
dd 0.03125 ; Sustain
|
||||
dd 16307 ; RandomSeed
|
||||
dd 1 ; Layers
|
||||
dd 4096.0 ; Index
|
||||
dd 0.125 ; Index Spread
|
||||
dd 0.0009765625 ; M Detune
|
||||
dd 0.0009765625 ; B Detune
|
||||
dd 65536 ; ModWave
|
||||
dd 65536 ; BaseWave
|
||||
|
||||
struc instr_params
|
||||
ip_basewave: resd 1
|
||||
ip_modwave: resd 1
|
||||
ip_bdetune: resd 1
|
||||
ip_mdetune: resd 1
|
||||
ip_indexspr: resd 1
|
||||
ip_index: resd 1
|
||||
ip_layers: resd 1
|
||||
ip_randomseed: resd 1
|
||||
ip_sustain: resd 1
|
||||
ip_volume: resd 1+USES_PANNING
|
||||
ip_bpitch: resd 1
|
||||
ip_mpitch: resd 1
|
||||
ip_bpitchd: resd 1
|
||||
ip_mpitchd: resd 1
|
||||
%if USES_INDEXDECAY
|
||||
ip_indexd: resd 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
ip_gain: resd 1
|
||||
%endif
|
||||
ip_attack: resd 1
|
||||
ip_decay: resd 1
|
||||
ip_release: resd 1
|
||||
endstruc
|
||||
|
||||
%define ip_INT 0
|
||||
%define ip_FLOAT 0
|
||||
%define IP(f,t) dword [instrparams + ip_ %+ f + ip_ %+ t]
|
||||
%define IPI(f,i,t) dword [instrparams + ip_ %+ f + ip_ %+ t + i]
|
||||
|
||||
|
||||
;; ********** Internal constants and tables **********
|
||||
|
||||
section resamp rdata align=4
|
||||
resamplefilter:
|
||||
db -1,-2,-4,-4,-2,3,14,30,51,98,116,126
|
||||
db 126,116,98,51,30,14,3,-2,-4,-4,-2,-1
|
||||
resamplefilter_end:
|
||||
FILTER_SIZE equ (resamplefilter_end-resamplefilter)
|
||||
|
||||
section wavestep rdata align=4
|
||||
c_wavestep: dd 0.000030517578125
|
||||
section basefreq rdata align=4
|
||||
c_basefreq: dd 2.86698696365342
|
||||
section halfnote rdata align=4
|
||||
c_halfnote: dd 1.05946309435929
|
||||
section finalamp rdata align=4
|
||||
c_finalamp: dd 32767
|
||||
section velfac rdata align=4
|
||||
c_velocityfac: dd 0.007874015748031496
|
||||
section delaystr rdata align=4
|
||||
c_delaystr: dd DELAY_STRENGTH
|
||||
section offset rdata align=4
|
||||
c_timeoffset: dd CLINKSTER_TIMER_OFFSET*4
|
||||
section tempo rdata align=4
|
||||
c_ticklength: dd SUBSAMPLES_PER_TICK/4*4
|
||||
section half rdata align=4
|
||||
c_onehalf: dd 0.5
|
||||
|
||||
|
||||
;; ********** Internal global variables **********
|
||||
|
||||
section vars bss align=8
|
||||
vars_align16
|
||||
|
||||
layer_random: resd 1
|
||||
stereo: resd 1 ; 0 for left channel, 2 for right channel
|
||||
noteposptr: resd 1
|
||||
notesamptr: resd 1
|
||||
|
||||
instrparams:
|
||||
resb instr_params_size
|
||||
|
||||
layer_params:
|
||||
layer_bfreq: resq 1
|
||||
layer_mfreq: resq 1
|
||||
layer_index: resq 1
|
||||
layer_bpitch: resq 1
|
||||
layer_mpitch: resq 1
|
||||
layer_bpitchd: resq 1
|
||||
layer_mpitchd: resq 1
|
||||
%if USES_INDEXDECAY
|
||||
layer_indexd: resq 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
layer_gain: resq 1
|
||||
%endif
|
||||
layer_attack: resq 1
|
||||
layer_decay: resq 1
|
||||
layer_release: resq 1
|
||||
layer_phasetmp: resd 1
|
||||
|
||||
|
||||
;; ********** Generate the sound for one layer **********
|
||||
|
||||
section mklayer text align=1
|
||||
makelayer:
|
||||
mov edx, layer_params
|
||||
|
||||
; Init random variables for layer
|
||||
fild word [layer_random]
|
||||
mov ecx, dword [layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [layer_random], ecx
|
||||
|
||||
fld IP(bdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [layer_random]
|
||||
mov ecx, dword [layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [layer_random], ecx
|
||||
|
||||
fld IP(mdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [layer_random]
|
||||
mov ecx, dword [layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [layer_random], ecx
|
||||
|
||||
fmul IP(indexspr, FLOAT)
|
||||
fadd IP(index, FLOAT)
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
; Init exponentiated variables for layer
|
||||
mov edi, instrparams+ip_bpitch
|
||||
mov ecx, 7+USES_INDEXDECAY+USES_GAIN
|
||||
.powloop:
|
||||
fld dword [edi]
|
||||
|
||||
fld1
|
||||
fld st1
|
||||
fprem
|
||||
fstp st1
|
||||
f2xm1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fscale
|
||||
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
fstp st0
|
||||
scasd
|
||||
loop .powloop
|
||||
|
||||
mov ebx, edx ; phasetmp
|
||||
|
||||
; Loop over samples
|
||||
fldz ; b phase
|
||||
fldz ; m phase
|
||||
mov edi, _InstrumentBuffer
|
||||
|
||||
; Calculate max note size
|
||||
xor eax, eax
|
||||
%if USES_VELOCITY
|
||||
lodsb ; Skip velocity
|
||||
%endif
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; Length of longest note with this tone
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
add eax, MAX_RELEASE_SUBSAMPLES
|
||||
xchg ecx, eax
|
||||
|
||||
.sampleloop:
|
||||
mov edx, layer_params
|
||||
|
||||
; Look up mod wave
|
||||
fist dword [ebx]
|
||||
mov eax, IP(modwave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Adjust by index
|
||||
fmul qword [edx + 2*8] ; layer_index
|
||||
fadd st0, st2
|
||||
|
||||
; Look up base wave
|
||||
fistp dword [ebx]
|
||||
mov eax, IP(basewave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Update phases
|
||||
fld qword [edx] ; layer_bfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_bpitch
|
||||
faddp st3, st0
|
||||
|
||||
fld qword [edx] ; layer_mfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_mpitch
|
||||
faddp st2, st0
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fld qword [edx] ; layer_index
|
||||
fld1
|
||||
fadd st1, st0
|
||||
fsubp st1, st0
|
||||
%endif
|
||||
add edx, byte 8
|
||||
|
||||
; Update pitches: p := (p-1)*d+1
|
||||
fld1
|
||||
fld qword [edx] ; layer_bpitch
|
||||
fsub st0, st1
|
||||
fmul qword [edx + 2*8] ; layer_bpitchd
|
||||
faddp st1, st0
|
||||
fstp qword [edx] ; layer_bpitch
|
||||
add edx, byte 8
|
||||
|
||||
fld1
|
||||
fld qword [edx] ; layer_mpitch
|
||||
fsub st0, st1
|
||||
fmul qword [edx + 2*8] ; layer_mpitchd
|
||||
faddp st1, st0
|
||||
fstp qword [edx] ; layer_mpitch
|
||||
add edx, byte 8
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fmul qword [edx + 2*8] ; layer_indexd
|
||||
fstp qword [edx - 3*8] ; layer_index
|
||||
%endif
|
||||
|
||||
; Add to existing layers
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
|
||||
loop .sampleloop
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Interpolate one section of amplitude envelope **********
|
||||
|
||||
section adsr text align=1
|
||||
apply_adsr:
|
||||
; On condition g:
|
||||
; st0 = amplitude target
|
||||
; st1 = amplitude
|
||||
; st2 = velocity / nlayers
|
||||
; eax = number of samples
|
||||
; ecx = sample index
|
||||
; On condition le:
|
||||
; st0 = number of samples
|
||||
; st1 = amplitude target
|
||||
; st2 = amplitude
|
||||
; st3 = velocity / nlayers
|
||||
; ecx = sample index
|
||||
|
||||
push eax
|
||||
jg .integer_length
|
||||
fimul dword [c_finalamp]
|
||||
fistp dword [esp]
|
||||
.integer_length:
|
||||
fsub st0, st1
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
add eax, ecx
|
||||
fdivp st1, st0
|
||||
|
||||
.adsrloop:
|
||||
fld dword [_InstrumentBuffer + ecx*4]
|
||||
fmul st0, st3 ; velocity / nlayers
|
||||
fmul st0, st2 ; envelope value
|
||||
|
||||
%if USES_GAIN
|
||||
fld1
|
||||
fsubr qword [layer_gain]
|
||||
fmul st0, st1
|
||||
fmul st0, st1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fdivr qword [layer_gain]
|
||||
fsqrt
|
||||
fmulp st1, st0
|
||||
%endif
|
||||
|
||||
fstp dword [_InstrumentRender + ecx*4]
|
||||
|
||||
fadd st1, st0
|
||||
inc ecx
|
||||
|
||||
cmp ecx, eax
|
||||
jl .adsrloop
|
||||
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Main music generation **********
|
||||
|
||||
section genMus text align=1
|
||||
Clinkster_GenerateMusic:
|
||||
_Clinkster_GenerateMusic@0:
|
||||
pusha
|
||||
fninit
|
||||
|
||||
; Make waveforms
|
||||
mov edi, waveforms
|
||||
%if USES_SINE
|
||||
fldz
|
||||
mov ecx, WAVE_SIZE
|
||||
.sineloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .sineloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SAWTOOTH
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.sawtoothloop:
|
||||
fadd dword [c_wavestep]
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .sawtoothloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SQUARE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.squareloop:
|
||||
cmp ecx, WAVE_SIZE/2
|
||||
jne .notflipsq
|
||||
fabs
|
||||
.notflipsq:
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .squareloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_PARABOLA
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.parabolaloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fmul st0, st1
|
||||
fadd st0, st0
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .parabolaloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_TRIANGLE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.triangleloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fadd st0, st1
|
||||
fabs
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .triangleloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_NOISE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.noiseloop:
|
||||
fadd dword [c_wavestep]
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .noiseloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
.stereoloop:
|
||||
mov dword [noteposptr], _NotePositions
|
||||
mov dword [notesamptr], _NoteSamples
|
||||
|
||||
xor eax, eax
|
||||
mov edi, _MixingBuffer
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
rep stosd
|
||||
|
||||
mov esi, _InstrumentData
|
||||
%if USES_DELAY
|
||||
jmp short .trackloop
|
||||
|
||||
.delay:
|
||||
mov eax, dword [stereo]
|
||||
mov edx, (LEFT_DELAY_LENGTH-RIGHT_DELAY_LENGTH)*4/2
|
||||
mul edx
|
||||
sub eax, LEFT_DELAY_LENGTH*4
|
||||
mov edi, _MixingBuffer
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
.delayloop:
|
||||
fld dword [edi+eax]
|
||||
fmul dword [c_delaystr]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .delayloop
|
||||
%endif
|
||||
|
||||
.trackloop:
|
||||
; ESI = instr data
|
||||
mov edi, instrparams
|
||||
mov ecx, instr_params_size/4
|
||||
.ploop:
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [param_weights-4+ecx*4]
|
||||
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .ploop
|
||||
|
||||
mov edi, instrparams+ip_bpitchd
|
||||
mov ecx, 2+USES_INDEXDECAY
|
||||
.cubeloop:
|
||||
fld dword [edi]
|
||||
fld st0
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .cubeloop
|
||||
|
||||
mov ebx, _InstrumentPointers
|
||||
mov dword [ebx], _InstrumentStore ; store first instrument instance address
|
||||
fld dword [c_basefreq]
|
||||
|
||||
; Loop over instrument tones
|
||||
.toneloop:
|
||||
xor eax, eax
|
||||
lodsb ; Tone
|
||||
.freqloop:
|
||||
fmul dword [c_halfnote]
|
||||
dec eax
|
||||
jge .freqloop
|
||||
|
||||
; random seed for channel = RandomSeed * 16307 + channel * 12042
|
||||
mov eax, dword [stereo]
|
||||
mov edx, 12042/2
|
||||
mul edx
|
||||
add eax, IP(randomseed,INT)
|
||||
xchg ecx, eax
|
||||
mov dword [layer_random], ecx
|
||||
|
||||
xor eax, eax
|
||||
mov edi, _InstrumentBuffer
|
||||
mov ecx, MAX_INSTRUMENT_SUBSAMPLES
|
||||
rep stosd
|
||||
|
||||
; Loop over layers
|
||||
mov ecx, IP(layers,INT)
|
||||
.layerloop:
|
||||
pusha
|
||||
|
||||
call makelayer
|
||||
|
||||
popa
|
||||
loop .layerloop
|
||||
|
||||
.lengthloop:
|
||||
%if USES_VELOCITY
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [c_velocityfac]
|
||||
%else
|
||||
fld1
|
||||
%endif
|
||||
fidiv IP(layers,INT)
|
||||
|
||||
xor ecx, ecx ; sample index
|
||||
fldz ; amplitude level
|
||||
|
||||
fld1 ; attack amplitude target
|
||||
fld qword [layer_attack]; attack length
|
||||
call apply_adsr
|
||||
|
||||
fld IP(sustain,FLOAT) ; decay amplitude target
|
||||
fld qword [layer_decay] ; decay length
|
||||
call apply_adsr
|
||||
|
||||
xor eax, eax
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; note length in ticks
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
sub eax, ecx ; note length exclusing attack and decay
|
||||
jle .nosustain ; attack + decay overflows note length
|
||||
fld IP(sustain,FLOAT) ; sustain amplitude target
|
||||
call apply_adsr
|
||||
.nosustain:
|
||||
|
||||
fldz ; release amplitude target
|
||||
fld qword [layer_release];release length
|
||||
call apply_adsr
|
||||
|
||||
fldz ; padding amplitude
|
||||
fld1 ; padding length
|
||||
call apply_adsr
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
|
||||
; Resampling
|
||||
mov edi, [ebx] ; instrument instance address
|
||||
add ebx, byte 4
|
||||
|
||||
xchg edx, eax
|
||||
mov ebp, _InstrumentRender - FILTER_SIZE*4
|
||||
.resampleloop:
|
||||
fldz
|
||||
mov ecx, FILTER_SIZE
|
||||
.filterloop:
|
||||
movsx eax, byte [resamplefilter + ecx - 1]
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [ebp + ecx*4]
|
||||
faddp st1, st0
|
||||
loop .filterloop
|
||||
|
||||
%if USES_PANNING
|
||||
mov eax, dword [stereo]
|
||||
fmul IPI(volume,eax*2,FLOAT)
|
||||
%else
|
||||
fmul IP(volume,FLOAT)
|
||||
%endif
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add ebp, byte 4*4
|
||||
|
||||
sub edx, byte 4
|
||||
jg .resampleloop
|
||||
|
||||
mov [ebx], edi ; store instrument instance address
|
||||
|
||||
cmp [esi], byte 0
|
||||
jne near .lengthloop
|
||||
lodsb
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .toneloop
|
||||
lodsb
|
||||
fstp st0
|
||||
|
||||
; Mixing
|
||||
mov ebx, _InstrumentPointers
|
||||
mov ebp, _MixingBuffer
|
||||
xchg esi, dword [notesamptr]
|
||||
.noteloop:
|
||||
xchg esi, dword [noteposptr]
|
||||
xor eax, eax
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notepos
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notepos:
|
||||
lodsb
|
||||
mov edx, SUBSAMPLES_PER_TICK/4*4
|
||||
mul edx
|
||||
add ebp, eax
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, SUBSAMPLES_PER_TICK/4*4
|
||||
div ecx
|
||||
xchg edx, eax
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
mov ecx, edx
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
add eax, edx
|
||||
stosd
|
||||
%endif
|
||||
|
||||
xchg esi, dword [noteposptr]
|
||||
xor eax, eax
|
||||
lodsb
|
||||
mov edx, dword [ebx + eax*4] ; Instrument instance ptr
|
||||
mov edi, ebp
|
||||
|
||||
.mixloop:
|
||||
fld dword [edx]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add edx, byte 4
|
||||
|
||||
cmp edx, dword [ebx + eax*4 + 4]
|
||||
jl .mixloop
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .noteloop
|
||||
lodsb
|
||||
xchg esi, dword [notesamptr]
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, 1<<LOGNUMTICKS
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
sub ecx, eax
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
%endif
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .trackloop
|
||||
lodsb
|
||||
|
||||
%if USES_DELAY
|
||||
cmp [esi], byte 0
|
||||
jge near .delay
|
||||
%endif
|
||||
|
||||
; Clamp and convert to shorts
|
||||
fld1
|
||||
mov edi, Clinkster_MusicBuffer
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
add edi, dword [stereo]
|
||||
.sloop:
|
||||
fld dword [_MixingBuffer + ecx*4]
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
|
||||
fimul dword [c_finalamp]
|
||||
fistp word [edi + ecx*4]
|
||||
loop .sloop
|
||||
fstp st0
|
||||
|
||||
xor byte [stereo], 2
|
||||
jne .stereoloop
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Start music **********
|
||||
|
||||
section startmus text align=1
|
||||
Clinkster_StartMusic:
|
||||
_Clinkster_StartMusic@0:
|
||||
; Start music
|
||||
push byte 0
|
||||
push byte 0
|
||||
push byte 0
|
||||
push _WaveFormat
|
||||
push byte -1
|
||||
push _WaveOutHandle
|
||||
call [__imp__waveOutOpen@24]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle] ; waveOutHandle
|
||||
call [__imp__waveOutPrepareHeader@12]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutWrite@12]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get current play position **********
|
||||
|
||||
section getpos text align=1
|
||||
Clinkster_GetPosition:
|
||||
_Clinkster_GetPosition@0:
|
||||
push byte 32 ; sizeof(MMTIME)
|
||||
push _WaveTime
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutGetPosition@12]
|
||||
|
||||
fild dword [_WaveTime+4]
|
||||
%if CLINKSTER_TIMER_OFFSET>0
|
||||
fiadd dword [c_timeoffset]
|
||||
%endif
|
||||
fidiv dword [c_ticklength]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get time since instrument trigger **********
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section insttrig text align=1
|
||||
Clinkster_GetInstrumentTrigger:
|
||||
_Clinkster_GetInstrumentTrigger@8:
|
||||
cvttss2si eax, [esp+8]
|
||||
mov ecx, [esp+4]
|
||||
shl ecx, LOGNUMTICKS+2
|
||||
fld dword [esp+8]
|
||||
fisub dword [Clinkster_NoteTiming+ecx+eax*4]
|
||||
ret 8
|
||||
%endif
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef _CLINKSTER_H_
|
||||
#define _CLINKSTER_H_
|
||||
|
||||
struct sample {
|
||||
short left,right;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
// Generate the whole music in to music buffer. When this function
|
||||
// returns, Clinkster_MusicBuffer will be filled with sound data,
|
||||
// and Clinkster_StartMusic can be called.
|
||||
void __stdcall Clinkster_GenerateMusic();
|
||||
|
||||
// Play the music
|
||||
void __stdcall Clinkster_StartMusic();
|
||||
|
||||
// Returns how much of the music has currently been played.
|
||||
// Use this function as the timer for the visuals in your intro.
|
||||
// Returned value is measured in music ticks (pattern rows).
|
||||
float __stdcall Clinkster_GetPosition();
|
||||
|
||||
// Used for timing intro events to music notes.
|
||||
// Returns how long ago (in ticks) a note was last triggered in the
|
||||
// specified track, starting from the specified position (in ticks).
|
||||
// If the track contains no note before the specified position,
|
||||
// the position is returned back (as if there was a note at time 0).
|
||||
// Note that the track number refers to post-conversion track numbers.
|
||||
// Consult the text output from the conversion script to see at which
|
||||
// track each original track/instrument combination has ended up.
|
||||
float __stdcall Clinkster_GetInstrumentTrigger(int track, float position);
|
||||
|
||||
// Buffer containing the music.
|
||||
extern struct sample Clinkster_MusicBuffer[];
|
||||
|
||||
// The tick rate of the music.
|
||||
extern const float Clinkster_TicksPerSecond;
|
||||
|
||||
// The length of the music in ticks.
|
||||
extern const unsigned int Clinkster_MusicLength;
|
||||
|
||||
// The number of tracks in the music.
|
||||
extern const unsigned int Clinkster_NumTracks;
|
||||
|
||||
// Timing data used by Clinkster_GetInstrumentTrigger.
|
||||
// Consists of NUMTRACKS blocks of (1 << LOGNUMTICKS) ints
|
||||
// (constants defined in music.asm) where index i for a track
|
||||
// holds the last tick (at or prior to i) where a note was
|
||||
// triggered in that track.
|
||||
extern unsigned int Clinkster_TimingData[];
|
||||
|
||||
// Wav file header to use if you want to write the music to disk.
|
||||
// Write these 44 bytes followed by Clinkster_MusicBuffer with a
|
||||
// length of Clinkster_WavFileHeader[10].
|
||||
extern unsigned int Clinkster_WavFileHeader[11];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
extern Clinkster_GenerateMusic
|
||||
extern Clinkster_StartMusic
|
||||
extern Clinkster_GetPosition
|
||||
extern Clinkster_GetInstrumentTrigger
|
||||
|
||||
extern Clinkster_MusicBuffer
|
||||
extern Clinkster_NoteTiming
|
||||
extern Clinkster_TicksPerSecond
|
||||
extern Clinkster_MusicLength
|
||||
extern Clinkster_NumTracks
|
|
@ -0,0 +1,962 @@
|
|||
|
||||
; If set to 1, timing information is generated during music generation
|
||||
; which is needed for Clinkster_GetInstrumentTrigger.
|
||||
; Set it to 0 if you don't need this functionality.
|
||||
%define CLINKSTER_GENERATE_TIMING_DATA 0
|
||||
|
||||
; Offset applied by Clinkster_GetPosition to compensate for graphics latency.
|
||||
; Measured in samples (44100ths of a second).
|
||||
; The default value of 2048 (corresponding to about 46 milliseconds) is
|
||||
; appropriate for typical display latencies for high-framerate effects.
|
||||
%define CLINKSTER_TIMER_OFFSET 2048
|
||||
|
||||
%include "music.asm"
|
||||
|
||||
|
||||
;; ********** Definitions **********
|
||||
|
||||
global Clinkster_GenerateMusic
|
||||
global _Clinkster_GenerateMusic@0
|
||||
global Clinkster_StartMusic
|
||||
global _Clinkster_StartMusic@0
|
||||
global Clinkster_GetPosition
|
||||
global _Clinkster_GetPosition@0
|
||||
global Clinkster_GetInstrumentTrigger
|
||||
global _Clinkster_GetInstrumentTrigger@8
|
||||
|
||||
global Clinkster_MusicBuffer
|
||||
global _Clinkster_MusicBuffer
|
||||
global Clinkster_TicksPerSecond
|
||||
global _Clinkster_TicksPerSecond
|
||||
global Clinkster_MusicLength
|
||||
global _Clinkster_MusicLength
|
||||
global Clinkster_NumTracks
|
||||
global _Clinkster_NumTracks
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
global Clinkster_NoteTiming
|
||||
global _Clinkster_NoteTiming
|
||||
%endif
|
||||
global Clinkster_WavFileHeader
|
||||
global _Clinkster_WavFileHeader
|
||||
|
||||
extern __imp__waveOutOpen@24
|
||||
extern __imp__waveOutPrepareHeader@12
|
||||
extern __imp__waveOutWrite@12
|
||||
extern __imp__waveOutGetPosition@12
|
||||
|
||||
extern __imp__CreateThread@24
|
||||
extern __imp__WaitForSingleObject@8
|
||||
|
||||
%define SAMPLE_RATE 44100
|
||||
%define WAVE_SIZE 65536
|
||||
|
||||
|
||||
;; ********** Public variables **********
|
||||
|
||||
section MusBuf bss align=4
|
||||
Clinkster_MusicBuffer:
|
||||
_Clinkster_MusicBuffer:
|
||||
.align24
|
||||
resw (TOTAL_SAMPLES*2)
|
||||
resw 2 ; padding to catch extra write in conversion
|
||||
|
||||
section tps rdata align=4
|
||||
Clinkster_TicksPerSecond:
|
||||
_Clinkster_TicksPerSecond:
|
||||
dd TICKS_PER_SECOND
|
||||
|
||||
section muslen rdata align=4
|
||||
Clinkster_MusicLength:
|
||||
_Clinkster_MusicLength:
|
||||
dd MUSIC_LENGTH
|
||||
|
||||
section numtr rdata align=4
|
||||
Clinkster_NumTracks:
|
||||
_Clinkster_NumTracks:
|
||||
dd NUMTRACKS
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section musdat bss align=4
|
||||
Clinkster_NoteTiming:
|
||||
_Clinkster_NoteTiming:
|
||||
.align16
|
||||
resd 2*(NUMTRACKS<<LOGNUMTICKS)
|
||||
|
||||
section timing data align=4
|
||||
timing_ptr: dd Clinkster_NoteTiming
|
||||
%endif
|
||||
|
||||
section WavFile rdata align=4
|
||||
Clinkster_WavFileHeader:
|
||||
_Clinkster_WavFileHeader:
|
||||
db "RIFF"
|
||||
dd 36+TOTAL_SAMPLES*4
|
||||
db "WAVE"
|
||||
db "fmt "
|
||||
dd 16
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16
|
||||
db "data"
|
||||
dd TOTAL_SAMPLES*4
|
||||
|
||||
|
||||
;; ********** System structures **********
|
||||
|
||||
section WaveForm rdata align=1
|
||||
_WaveFormat:
|
||||
dw 1,2
|
||||
dd SAMPLE_RATE
|
||||
dd SAMPLE_RATE*4
|
||||
dw 4,16,0
|
||||
|
||||
section WaveHdr data align=4
|
||||
_WaveHdr:
|
||||
dd Clinkster_MusicBuffer
|
||||
dd (TOTAL_SAMPLES*4)
|
||||
dd 0,0,0,0,0,0
|
||||
|
||||
section wavehand bss align=4
|
||||
_WaveOutHandle:
|
||||
.align16
|
||||
resd 1
|
||||
|
||||
section WaveTime data align=4
|
||||
_WaveTime:
|
||||
dd 4,0,0,0,0,0,0,0
|
||||
|
||||
|
||||
;; ********** Internal buffers **********
|
||||
|
||||
section wforms bss align=4
|
||||
waveforms:
|
||||
.align16
|
||||
resd 6*WAVE_SIZE
|
||||
|
||||
|
||||
;; ********** Instrument parameter access **********
|
||||
|
||||
section paramw rdata align=4
|
||||
param_weights:
|
||||
dd 0.125 ; Release
|
||||
dd 0.125 ; Decay
|
||||
dd 0.125 ; Attack
|
||||
%if USES_GAIN
|
||||
dd 0.125 ; Gain
|
||||
%endif
|
||||
%if USES_INDEXDECAY
|
||||
dd 0.0009765625 ; IndexDecay
|
||||
%endif
|
||||
dd 0.0009765625 ; M PitchDecay
|
||||
dd 0.0009765625 ; B PitchDecay
|
||||
dd 0.083333333333 ; M Pitch
|
||||
dd 0.083333333333 ; B Pitch
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%if USES_PANNING
|
||||
dd 0.0000152587890625 ; Volume
|
||||
%endif
|
||||
dd 0.03125 ; Sustain
|
||||
dd 16307 ; RandomSeed
|
||||
dd 1 ; Layers
|
||||
dd 4096.0 ; Index
|
||||
dd 0.125 ; Index Spread
|
||||
dd 0.0009765625 ; M Detune
|
||||
dd 0.0009765625 ; B Detune
|
||||
dd 65536 ; ModWave
|
||||
dd 65536 ; BaseWave
|
||||
|
||||
struc instr_params
|
||||
ip_basewave: resd 1
|
||||
ip_modwave: resd 1
|
||||
ip_bdetune: resd 1
|
||||
ip_mdetune: resd 1
|
||||
ip_indexspr: resd 1
|
||||
ip_index: resd 1
|
||||
ip_layers: resd 1
|
||||
ip_randomseed: resd 1
|
||||
ip_sustain: resd 1
|
||||
ip_volume: resd 1+USES_PANNING
|
||||
ip_bpitch: resd 1
|
||||
ip_mpitch: resd 1
|
||||
ip_bpitchd: resd 1
|
||||
ip_mpitchd: resd 1
|
||||
%if USES_INDEXDECAY
|
||||
ip_indexd: resd 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
ip_gain: resd 1
|
||||
%endif
|
||||
ip_attack: resd 1
|
||||
ip_decay: resd 1
|
||||
ip_release: resd 1
|
||||
endstruc
|
||||
|
||||
%define ip_INT 0
|
||||
%define ip_FLOAT 0
|
||||
%define IP(f,t) dword [dword ebx + g_instrparams + ip_ %+ f + ip_ %+ t]
|
||||
%define IPI(f,i,t) dword [dword ebx + g_instrparams + ip_ %+ f + ip_ %+ t + i]
|
||||
|
||||
|
||||
;; ********** Internal constants and tables **********
|
||||
|
||||
section resamp rdata align=4
|
||||
resamplefilter:
|
||||
db -1,-2,-4,-4,-2,3,14,30,51,98,116,126
|
||||
db 126,116,98,51,30,14,3,-2,-4,-4,-2,-1
|
||||
resamplefilter_end:
|
||||
FILTER_SIZE equ (resamplefilter_end-resamplefilter)
|
||||
|
||||
section wavestep rdata align=4
|
||||
c_wavestep: dd 0.000030517578125
|
||||
section basefreq rdata align=4
|
||||
c_basefreq: dd 2.86698696365342
|
||||
section halfnote rdata align=4
|
||||
c_halfnote: dd 1.05946309435929
|
||||
section finalamp rdata align=4
|
||||
c_finalamp: dd 32767
|
||||
section velfac rdata align=4
|
||||
c_velocityfac: dd 0.007874015748031496
|
||||
section delaystr rdata align=4
|
||||
c_delaystr: dd DELAY_STRENGTH
|
||||
section offset rdata align=4
|
||||
c_timeoffset: dd CLINKSTER_TIMER_OFFSET*4
|
||||
section tempo rdata align=4
|
||||
c_ticklength: dd SUBSAMPLES_PER_TICK/4*4
|
||||
section half rdata align=4
|
||||
c_onehalf: dd 0.5
|
||||
|
||||
|
||||
;; ********** Internal global variables **********
|
||||
|
||||
struc globalvars
|
||||
g_phasetemp: resd 1
|
||||
g_layer_random: resd 1
|
||||
g_stereo: resd 1 ; 0 for left channel, 2 for right channel
|
||||
g_noteposptr: resd 1
|
||||
g_notesamptr: resd 1
|
||||
g_instrparams: resb instr_params_size
|
||||
g_layerparams: resq 0
|
||||
g_layer_bfreq: resq 1
|
||||
g_layer_mfreq: resq 1
|
||||
g_layer_index: resq 1
|
||||
g_layer_bpitch: resq 1
|
||||
g_layer_mpitch: resq 1
|
||||
g_layer_bpitchd: resq 1
|
||||
g_layer_mpitchd: resq 1
|
||||
%if USES_INDEXDECAY
|
||||
g_layer_indexd: resq 1
|
||||
%endif
|
||||
%if USES_GAIN
|
||||
g_layer_gain: resq 1
|
||||
%endif
|
||||
g_layer_attack: resq 1
|
||||
g_layer_decay: resq 1
|
||||
g_layer_release: resq 1
|
||||
|
||||
alignb 256
|
||||
g_InstrumentPointers:
|
||||
resd MAX_TRACK_INSTRUMENT_RENDERS+1
|
||||
|
||||
resd MAX_DELAY_LENGTH
|
||||
alignb 16777216
|
||||
g_MixingBuffer:
|
||||
resd TOTAL_SAMPLES
|
||||
|
||||
alignb 16777216
|
||||
g_InstrumentBuffer:
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
resd 256
|
||||
alignb 16777216
|
||||
g_InstrumentRender:
|
||||
resd MAX_INSTRUMENT_SUBSAMPLES
|
||||
|
||||
alignb 16777216
|
||||
g_InstrumentStore:
|
||||
resd MAX_TOTAL_INSTRUMENT_SAMPLES
|
||||
|
||||
endstruc
|
||||
|
||||
section vars bss align=8
|
||||
vars_align16
|
||||
globals:
|
||||
resb globalvars_size
|
||||
resb globalvars_size
|
||||
|
||||
|
||||
;; ********** Generate the sound for one layer **********
|
||||
|
||||
section mklayer text align=1
|
||||
makelayer:
|
||||
lea edx, [dword ebx + g_layerparams]
|
||||
|
||||
; Init random variables for layer
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fld IP(bdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fld IP(mdetune, FLOAT)
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fadd st0, st1
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
fild word [dword ebx + g_layer_random]
|
||||
mov ecx, dword [dword ebx + g_layer_random]
|
||||
ror ecx, cl
|
||||
dec ecx
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
fmul IP(indexspr, FLOAT)
|
||||
fadd IP(index, FLOAT)
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
|
||||
; Init exponentiated variables for layer
|
||||
lea edi, [dword ebx + g_instrparams+ip_bpitch]
|
||||
mov ecx, 7+USES_INDEXDECAY+USES_GAIN
|
||||
.powloop:
|
||||
fld dword [edi]
|
||||
|
||||
fld1
|
||||
fld st1
|
||||
fprem
|
||||
fstp st1
|
||||
f2xm1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fscale
|
||||
|
||||
fstp qword [edx]
|
||||
add edx, byte 8
|
||||
fstp st0
|
||||
scasd
|
||||
loop .powloop
|
||||
|
||||
; Loop over samples
|
||||
fldz ; b phase
|
||||
fldz ; m phase
|
||||
lea edi, [dword ebx + g_InstrumentBuffer]
|
||||
|
||||
; Calculate max note size
|
||||
xor eax, eax
|
||||
%if USES_VELOCITY
|
||||
lodsb ; Skip velocity
|
||||
%endif
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; Length of longest note with this tone
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
add eax, MAX_RELEASE_SUBSAMPLES
|
||||
xchg ecx, eax
|
||||
|
||||
.sampleloop:
|
||||
lea edx, [dword ebx + g_layerparams]
|
||||
|
||||
; Look up and normalize mod wave
|
||||
fist dword [ebx]
|
||||
mov eax, IP(modwave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Adjust by index
|
||||
fmul qword [edx + 2*8] ; layer_index
|
||||
fadd st0, st2
|
||||
|
||||
; Look up base wave
|
||||
fistp dword [ebx]
|
||||
mov eax, IP(basewave,INT)
|
||||
mov ax, [ebx]
|
||||
fld dword [waveforms + eax*4]
|
||||
|
||||
; Update phases
|
||||
fld qword [edx] ; layer_bfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_bpitch
|
||||
faddp st3, st0
|
||||
|
||||
fld qword [edx] ; layer_mfreq
|
||||
add edx, byte 8
|
||||
fmul qword [edx + 2*8] ; layer_mpitch
|
||||
faddp st2, st0
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fld qword [edx] ; layer_index
|
||||
fld1
|
||||
fadd st1, st0
|
||||
fsubp st1, st0
|
||||
%endif
|
||||
add edx, byte 8
|
||||
|
||||
; Update pitches: p := (p-1)*d+1
|
||||
.update:
|
||||
fld1
|
||||
fld qword [edx] ; layer_(b/m)pitch
|
||||
fsub st0, st1
|
||||
fmul qword [edx + 2*8] ; layer_(b/m)pitchd
|
||||
faddp st1, st0
|
||||
fstp qword [edx] ; layer_(b/m)pitch
|
||||
add edx, byte 8
|
||||
|
||||
neg ecx
|
||||
js .update
|
||||
|
||||
%if USES_INDEXDECAY
|
||||
fmul qword [edx + 2*8] ; layer_indexd
|
||||
fstp qword [edx - 3*8] ; layer_index
|
||||
%endif
|
||||
|
||||
; Add to existing layers
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
|
||||
loop .sampleloop
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Interpolate one section of amplitude envelope **********
|
||||
|
||||
section adsr text align=1
|
||||
apply_adsr:
|
||||
; On condition g:
|
||||
; st0 = amplitude target
|
||||
; st1 = amplitude
|
||||
; st2 = velocity / nlayers
|
||||
; eax = number of samples
|
||||
; ecx = sample index
|
||||
; On condition le:
|
||||
; st0 = number of samples
|
||||
; st1 = amplitude target
|
||||
; st2 = amplitude
|
||||
; st3 = velocity / nlayers
|
||||
; ecx = sample index
|
||||
|
||||
push eax
|
||||
jg .integer_length
|
||||
fimul dword [c_finalamp]
|
||||
fistp dword [esp]
|
||||
.integer_length:
|
||||
fsub st0, st1
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
add eax, ecx
|
||||
fdivp st1, st0
|
||||
|
||||
.adsrloop:
|
||||
fld dword [dword ebx + g_InstrumentBuffer + ecx*4]
|
||||
fmul st0, st3 ; velocity / nlayers
|
||||
fmul st0, st2 ; envelope value
|
||||
|
||||
%if USES_GAIN
|
||||
fld1
|
||||
fsubr qword [dword ebx + g_layer_gain]
|
||||
fmul st0, st1
|
||||
fmul st0, st1
|
||||
fld1
|
||||
faddp st1, st0
|
||||
fdivr qword [dword ebx + g_layer_gain]
|
||||
fsqrt
|
||||
fmulp st1, st0
|
||||
%endif
|
||||
|
||||
fstp dword [dword ebx + g_InstrumentRender + ecx*4]
|
||||
|
||||
fadd st1, st0
|
||||
inc ecx
|
||||
|
||||
cmp ecx, eax
|
||||
jl .adsrloop
|
||||
|
||||
fstp st0
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Main music generation **********
|
||||
|
||||
section genMus text align=1
|
||||
Clinkster_GenerateMusic:
|
||||
_Clinkster_GenerateMusic@0:
|
||||
pusha
|
||||
fninit
|
||||
|
||||
; Make waveforms
|
||||
mov edi, waveforms
|
||||
%if USES_SINE
|
||||
fldz
|
||||
mov ecx, WAVE_SIZE
|
||||
.sineloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .sineloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SAWTOOTH
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.sawtoothloop:
|
||||
fadd dword [c_wavestep]
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .sawtoothloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_SQUARE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.squareloop:
|
||||
cmp ecx, WAVE_SIZE/2
|
||||
jne .notflipsq
|
||||
fabs
|
||||
.notflipsq:
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .squareloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_PARABOLA
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.parabolaloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fmul st0, st1
|
||||
fadd st0, st0
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .parabolaloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_TRIANGLE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.triangleloop:
|
||||
fadd dword [c_wavestep]
|
||||
fld st0
|
||||
fadd st0, st1
|
||||
fabs
|
||||
fld1
|
||||
fsubp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .triangleloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
%if USES_NOISE
|
||||
fld1
|
||||
fchs
|
||||
mov ecx, WAVE_SIZE
|
||||
.noiseloop:
|
||||
fadd dword [c_wavestep]
|
||||
fldpi
|
||||
fmulp st1, st0
|
||||
fsin
|
||||
fst dword [edi]
|
||||
scasd
|
||||
loop .noiseloop
|
||||
fstp st0
|
||||
%endif
|
||||
|
||||
push byte 0 ; lpThreadId
|
||||
push byte 0 ; dwCreationFlags
|
||||
push byte 0 ; lpParameter
|
||||
push makechannel
|
||||
push byte 0 ; dwStackSize
|
||||
push byte 0 ; lpThreadAttributes
|
||||
call [__imp__CreateThread@24]
|
||||
|
||||
push byte -1
|
||||
push eax
|
||||
|
||||
push byte 2
|
||||
call makechannel
|
||||
|
||||
call [__imp__WaitForSingleObject@8]
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
makechannel:
|
||||
; eax = channel (0 or 2)
|
||||
mov eax, [esp + 4]
|
||||
mov edx, globalvars_size/2
|
||||
mul edx
|
||||
mov ebx, globals
|
||||
add ebx, eax
|
||||
mov eax, [esp + 4]
|
||||
mov [dword ebx + g_stereo], eax
|
||||
|
||||
mov dword [dword ebx + g_noteposptr], _NotePositions
|
||||
mov dword [dword ebx + g_notesamptr], _NoteSamples
|
||||
|
||||
mov esi, _InstrumentData
|
||||
%if USES_DELAY
|
||||
jmp short .trackloop
|
||||
|
||||
.delay:
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
mov edx, (LEFT_DELAY_LENGTH-RIGHT_DELAY_LENGTH)*4/2
|
||||
mul edx
|
||||
sub eax, LEFT_DELAY_LENGTH*4
|
||||
lea edi, [dword ebx + g_MixingBuffer]
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
.delayloop:
|
||||
fld dword [edi+eax]
|
||||
fmul dword [c_delaystr]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .delayloop
|
||||
%endif
|
||||
|
||||
.trackloop:
|
||||
; ESI = instr data
|
||||
lea edi, [dword ebx + g_instrparams]
|
||||
mov ecx, instr_params_size/4
|
||||
.ploop:
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [param_weights-4+ecx*4]
|
||||
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .ploop
|
||||
|
||||
lea edi, [dword ebx + g_instrparams+ip_bpitchd]
|
||||
mov ecx, 2+USES_INDEXDECAY
|
||||
.cubeloop:
|
||||
fld dword [edi]
|
||||
fld st0
|
||||
fmul st0, st0
|
||||
fmulp st1, st0
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
loop .cubeloop
|
||||
|
||||
lea ebp, [dword ebx + g_InstrumentPointers]
|
||||
lea edi, [dword ebx + g_InstrumentStore]
|
||||
mov dword [ebp], edi ; store first instrument instance address
|
||||
fld dword [c_basefreq]
|
||||
|
||||
; Loop over instrument tones
|
||||
.toneloop:
|
||||
xor eax, eax
|
||||
lodsb ; Tone
|
||||
.freqloop:
|
||||
fmul dword [c_halfnote]
|
||||
dec eax
|
||||
jge .freqloop
|
||||
|
||||
; random seed for channel = RandomSeed * 16307 + channel * 12042
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
mov edx, 12042/2
|
||||
mul edx
|
||||
add eax, IP(randomseed,INT)
|
||||
xchg ecx, eax
|
||||
mov dword [dword ebx + g_layer_random], ecx
|
||||
|
||||
xor eax, eax
|
||||
lea edi, [dword ebx + g_InstrumentBuffer]
|
||||
mov ecx, MAX_INSTRUMENT_SUBSAMPLES
|
||||
rep stosd
|
||||
|
||||
; Loop over layers
|
||||
mov ecx, IP(layers,INT)
|
||||
.layerloop:
|
||||
pusha
|
||||
|
||||
call makelayer
|
||||
|
||||
popa
|
||||
loop .layerloop
|
||||
|
||||
.lengthloop:
|
||||
%if USES_VELOCITY
|
||||
lodsb
|
||||
movsx eax, al
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [c_velocityfac]
|
||||
%else
|
||||
fld1
|
||||
%endif
|
||||
fidiv IP(layers,INT)
|
||||
|
||||
xor ecx, ecx ; sample index
|
||||
fldz ; amplitude level
|
||||
|
||||
fld1 ; attack amplitude target
|
||||
fld qword [dword ebx + g_layer_attack]; attack length
|
||||
call apply_adsr
|
||||
|
||||
fld IP(sustain,FLOAT) ; decay amplitude target
|
||||
fld qword [dword ebx + g_layer_decay] ; decay length
|
||||
call apply_adsr
|
||||
|
||||
xor eax, eax
|
||||
%if USES_LONG_NOTES
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notelen
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notelen:
|
||||
%endif
|
||||
lodsb ; note length in ticks
|
||||
mov edx, SUBSAMPLES_PER_TICK
|
||||
mul edx
|
||||
sub eax, ecx ; note length exclusing attack and decay
|
||||
jle .nosustain ; attack + decay overflows note length
|
||||
fld IP(sustain,FLOAT) ; sustain amplitude target
|
||||
call apply_adsr
|
||||
.nosustain:
|
||||
|
||||
fldz ; release amplitude target
|
||||
fld qword [dword ebx + g_layer_release];release length
|
||||
call apply_adsr
|
||||
|
||||
fldz ; padding amplitude
|
||||
fld1 ; padding length
|
||||
call apply_adsr
|
||||
|
||||
fstp st0
|
||||
fstp st0
|
||||
|
||||
; Resampling
|
||||
push esi
|
||||
mov edi, [ebp] ; instrument instance address
|
||||
add ebp, byte 4
|
||||
|
||||
xchg edx, eax
|
||||
lea esi, [dword ebx + g_InstrumentRender - FILTER_SIZE*4]
|
||||
.resampleloop:
|
||||
fldz
|
||||
mov ecx, FILTER_SIZE
|
||||
.filterloop:
|
||||
movsx eax, byte [resamplefilter + ecx - 1]
|
||||
push eax
|
||||
fild dword [esp]
|
||||
pop eax
|
||||
fmul dword [esi + ecx*4]
|
||||
faddp st1, st0
|
||||
loop .filterloop
|
||||
|
||||
%if USES_PANNING
|
||||
mov eax, dword [dword ebx + g_stereo]
|
||||
fmul IPI(volume,eax*2,FLOAT)
|
||||
%else
|
||||
fmul IP(volume,FLOAT)
|
||||
%endif
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add esi, byte 4*4
|
||||
|
||||
sub edx, byte 4
|
||||
jg .resampleloop
|
||||
|
||||
mov [ebp], edi ; store instrument instance address
|
||||
pop esi
|
||||
|
||||
cmp [esi], byte 0
|
||||
jne near .lengthloop
|
||||
lodsb
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .toneloop
|
||||
lodsb
|
||||
fstp st0
|
||||
|
||||
; Mixing
|
||||
lea ebp, [dword ebx + g_MixingBuffer]
|
||||
xchg esi, dword [dword ebx + g_notesamptr]
|
||||
.noteloop:
|
||||
xchg esi, dword [dword ebx + g_noteposptr]
|
||||
xor eax, eax
|
||||
cmp [esi], byte 0
|
||||
jge near .short_notepos
|
||||
lodsb
|
||||
not al
|
||||
shl eax, 8
|
||||
.short_notepos:
|
||||
lodsb
|
||||
mov edx, SUBSAMPLES_PER_TICK/4*4
|
||||
mul edx
|
||||
add ebp, eax
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, SUBSAMPLES_PER_TICK/4*4
|
||||
div ecx
|
||||
xchg edx, eax
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
mov ecx, edx
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
add eax, edx
|
||||
stosd
|
||||
%endif
|
||||
|
||||
xchg esi, dword [dword ebx + g_noteposptr]
|
||||
xor eax, eax
|
||||
lodsb
|
||||
mov edx, dword [dword ebx + g_InstrumentPointers + eax*4] ; Instrument instance ptr
|
||||
mov edi, ebp
|
||||
|
||||
.mixloop:
|
||||
fld dword [edx]
|
||||
fadd dword [edi]
|
||||
fstp dword [edi]
|
||||
scasd
|
||||
add edx, byte 4
|
||||
|
||||
cmp edx, dword [dword ebx + g_InstrumentPointers + eax*4 + 4]
|
||||
jl .mixloop
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .noteloop
|
||||
lodsb
|
||||
xchg esi, dword [dword ebx + g_notesamptr]
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
mov ecx, 1<<LOGNUMTICKS
|
||||
mov edi, [timing_ptr]
|
||||
mov eax, [edi]
|
||||
sub ecx, eax
|
||||
rep stosd
|
||||
mov [timing_ptr], edi
|
||||
%endif
|
||||
|
||||
cmp [esi], byte 0
|
||||
jge near .trackloop
|
||||
lodsb
|
||||
|
||||
%if USES_DELAY
|
||||
cmp [esi], byte 0
|
||||
jge near .delay
|
||||
%endif
|
||||
|
||||
; Clamp and convert to shorts
|
||||
fld1
|
||||
mov edi, Clinkster_MusicBuffer
|
||||
mov ecx, TOTAL_SAMPLES
|
||||
add edi, dword [dword ebx + g_stereo]
|
||||
.sloop:
|
||||
fld dword [dword ebx + g_MixingBuffer + ecx*4]
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
fcomi st0, st1
|
||||
fcmovnb st0, st1
|
||||
fchs
|
||||
|
||||
fimul dword [c_finalamp]
|
||||
fistp word [edi + ecx*4]
|
||||
loop .sloop
|
||||
fstp st0
|
||||
ret 4
|
||||
|
||||
|
||||
;; ********** Start music **********
|
||||
|
||||
section startmus text align=1
|
||||
Clinkster_StartMusic:
|
||||
_Clinkster_StartMusic@0:
|
||||
; Start music
|
||||
push byte 0
|
||||
push byte 0
|
||||
push byte 0
|
||||
push _WaveFormat
|
||||
push byte -1
|
||||
push _WaveOutHandle
|
||||
call [__imp__waveOutOpen@24]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle] ; waveOutHandle
|
||||
call [__imp__waveOutPrepareHeader@12]
|
||||
|
||||
push byte 32 ; sizeof(WAVEHDR)
|
||||
push _WaveHdr
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutWrite@12]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get current play position **********
|
||||
|
||||
section getpos text align=1
|
||||
Clinkster_GetPosition:
|
||||
_Clinkster_GetPosition@0:
|
||||
push byte 32 ; sizeof(MMTIME)
|
||||
push _WaveTime
|
||||
push dword [_WaveOutHandle]
|
||||
call [__imp__waveOutGetPosition@12]
|
||||
|
||||
fild dword [_WaveTime+4]
|
||||
%if CLINKSTER_TIMER_OFFSET>0
|
||||
fiadd dword [c_timeoffset]
|
||||
%endif
|
||||
fidiv dword [c_ticklength]
|
||||
ret
|
||||
|
||||
|
||||
;; ********** Get time since instrument trigger **********
|
||||
|
||||
%if CLINKSTER_GENERATE_TIMING_DATA
|
||||
section insttrig text align=1
|
||||
Clinkster_GetInstrumentTrigger:
|
||||
_Clinkster_GetInstrumentTrigger@8:
|
||||
cvttss2si eax, [esp+8]
|
||||
mov ecx, [esp+4]
|
||||
shl ecx, LOGNUMTICKS+2
|
||||
fld dword [esp+8]
|
||||
fisub dword [Clinkster_NoteTiming+ecx+eax*4]
|
||||
ret 8
|
||||
%endif
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
; Implementation of float-to-integer conversion as needed by MSVC.
|
||||
|
||||
global __ftol2
|
||||
global __ftol2_sse
|
||||
|
||||
section ftol text
|
||||
|
||||
__ftol2:
|
||||
__ftol2_sse:
|
||||
push eax
|
||||
fisttp dword [esp]
|
||||
pop eax
|
||||
cdq
|
||||
ret
|
|
@ -0,0 +1,766 @@
|
|||
; Clinkster music converted from examples/songs/Punqtured-Clinksterizer.xrns 2015-10-31 19:12:27
|
||||
|
||||
%define USES_SINE 1
|
||||
%define USES_SAWTOOTH 1
|
||||
%define USES_SQUARE 1
|
||||
%define USES_PARABOLA 1
|
||||
%define USES_TRIANGLE 1
|
||||
%define USES_NOISE 1
|
||||
%define USES_VELOCITY 1
|
||||
%define USES_LONG_NOTES 0
|
||||
%define USES_DELAY 1
|
||||
%define USES_PANNING 0
|
||||
%define USES_INDEXDECAY 1
|
||||
%define USES_GAIN 1
|
||||
|
||||
%define SUBSAMPLES_PER_TICK 17404
|
||||
%define MAX_INSTRUMENT_SUBSAMPLES 1638400
|
||||
%define MAX_TOTAL_INSTRUMENT_SAMPLES 2555904
|
||||
%define MAX_RELEASE_SUBSAMPLES 262144
|
||||
%define TOTAL_SAMPLES 7077888
|
||||
%define MAX_TRACK_INSTRUMENT_RENDERS 66
|
||||
|
||||
%define MAX_DELAY_LENGTH 13053
|
||||
%define LEFT_DELAY_LENGTH 8687
|
||||
%define RIGHT_DELAY_LENGTH 13053
|
||||
%define DELAY_STRENGTH 0.53555790
|
||||
|
||||
%define NUMTRACKS 17
|
||||
%define LOGNUMTICKS 11
|
||||
%define MUSIC_LENGTH 1600
|
||||
%define TICKS_PER_SECOND 10.13333333
|
||||
|
||||
|
||||
section instdata data align=1
|
||||
|
||||
_InstrumentData:
|
||||
; 00: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
db 4,3,9,13,0,19,11,40,9,61,0,0,0,-50,-61,-24,-38,-3,-9
|
||||
db 53,127,1,0,1,127,1,0,1,127,6,127,1,0,1,127,1,0,0,127,1,0,1,127,1,0,1,48,1,64,1,127,1,0,0,48,1,0,1,64,1,80,1,96,1,112,1,127,1,0,1,48,1,127,1,0,1,48,1,80,1,96,1,112,1,127,1,0,0,64,1,80,1,96,1,127,4,127,1,0,1,48,1,80,1,112,1,127,1,0,1,48,1,96,1,112,1,0,0,64,1,80,1,127,1,0,1,48,1,64,1,80,1,112,1,127,1,0,3,80,1,127,1,0,-1
|
||||
; 01: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
db 4,3,9,13,0,19,11,40,9,61,0,0,0,-50,-61,-24,-38,-3,-9
|
||||
db 55,127,1,0,3,127,1,0,2,127,2,0,4,127,1,0,1,127,6,127,1,0,1,127,1,0,0,127,1,0,1,64,1,127,1,0,1,48,1,64,1,96,1,0,0,48,1,127,1,0,1,64,1,80,1,96,1,112,1,127,1,0,1,48,1,64,1,127,1,0,1,48,1,80,1,96,1,112,1,127,1,0,0,64,1,80,1,96,1,127,1,0,1,48,1,80,1,112,1,127,1,0,1,48,1,96,1,112,1,0,0,64,1,80,1,127,1,0,1,48,1,64,1,80,1,112,1,127,1,0,3,80,1,127,1,0,-1
|
||||
; 02: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
db 4,3,9,13,0,19,11,40,9,61,0,0,0,-50,-61,-24,-38,-3,-9
|
||||
db 57,127,1,0,4,127,1,0,4,127,1,0,3,127,1,0,0,127,1,0,1,127,8,127,1,0,1,127,4,127,1,0,2,127,8,127,6,127,1,0,3,127,1,0,0,127,1,0,-1
|
||||
; 03: Track 02 / 09|VST: Clinkster (Basic)
|
||||
db 2,2,11,15,61,56,12,34,16,57,0,12,0,0,-67,-31,-17,-3,10
|
||||
db 76,127,2,0,2,127,2,0,1,127,10,127,2,0,1,127,4,0,0,127,6,127,4,0,1,127,24,127,8,127,4,0,1,127,6,127,4,127,2,0,0,127,6,127,4,0,1,127,24,127,12,127,8,127,2,0,1,127,4,127,2,0,1,127,4,127,2,0,0,127,2,0,-1
|
||||
; 04: Scream / 04|VST: Clinkster (Basic)
|
||||
db 2,4,5,11,100,1,28,62,32,8,48,0,0,-20,-36,1,-3,-5,-27
|
||||
db 19,127,20,0,11,127,20,0,1,127,14,0,-1
|
||||
; 05: Scream / 04|VST: Clinkster (Basic)
|
||||
db 2,4,5,11,100,1,28,62,32,8,48,0,0,-20,-36,1,-3,-5,-27
|
||||
db 31,127,20,0,11,127,20,0,1,127,14,0,-1
|
||||
; 06: Scream / 04|VST: Clinkster (Basic)
|
||||
db 2,4,5,11,100,1,28,62,32,8,48,0,0,-20,-36,1,-3,-5,-27
|
||||
db 43,127,20,0,11,127,16,0,-1
|
||||
db -1
|
||||
; 07: Strings / 06|VST: Clinkster (Basic)
|
||||
db 1,2,2,6,94,42,25,13,18,30,0,0,0,0,-20,-3,-13,3,16
|
||||
db 57,127,1,0,4,64,64,64,48,64,16,127,64,127,52,127,48,127,16,127,1,0,1,64,16,127,16,127,1,0,2,127,1,0,1,64,16,64,8,127,16,127,8,127,1,0,-1
|
||||
; 08: Strings / 06|VST: Clinkster (Basic)
|
||||
db 1,2,2,6,94,42,25,13,18,30,0,0,0,0,-20,-3,-13,3,16
|
||||
db 59,127,32,127,20,127,16,127,1,0,0,64,64,64,16,127,64,127,16,127,1,0,6,127,48,127,1,0,3,64,16,127,8,127,1,0,-1
|
||||
; 09: Strings / 06|VST: Clinkster (Basic)
|
||||
db 1,2,2,6,94,42,25,13,18,30,0,0,0,0,-20,-3,-13,3,16
|
||||
db 57,64,16,127,16,127,1,0,1,64,16,127,16,127,1,0,5,64,14,127,64,127,14,127,1,0,1,127,1,0,1,127,1,0,1,127,48,0,2,127,20,127,1,0,4,127,4,0,3,127,8,0,0,127,8,127,4,0,1,127,12,0,-1
|
||||
; 10: Strings / 06|VST: Clinkster (Basic)
|
||||
db 1,2,2,6,94,42,25,13,18,30,0,0,0,0,-20,-3,-13,3,16
|
||||
db 67,64,72,64,56,64,24,80,8,127,72,127,60,127,56,127,24,127,1,0,-1
|
||||
; 11: Long Bass / 01|VST: Clinkster (Basic)
|
||||
db 0,3,4,2,86,55,17,64,-30,30,0,12,0,-65,-20,3,-10,16,3
|
||||
db 29,96,16,127,16,0,1,96,32,127,52,127,32,127,24,0,1,96,16,127,16,0,1,96,16,127,16,0,0,96,16,127,16,0,-1
|
||||
; 12: Bassdrum / 02|VST: Clinkster (Basic)
|
||||
db 0,4,0,0,11,2,49,0,0,30,42,43,-70,-70,-49,1,-59,2,-27
|
||||
db 12,127,1,0,11,64,1,96,1,127,1,0,11,127,1,0,-1
|
||||
; 13: Zap / 03|VST: Clinkster (Basic)
|
||||
db 0,0,5,9,100,80,3,77,9,30,-12,36,-47,-70,-67,-27,-59,-9,-11
|
||||
db 30,127,1,0,6,127,1,0,4,64,1,80,1,0,6,48,1,0,4,32,1,0,-1
|
||||
; 14: Counter Bass / 05|VST: Clinkster (Basic)
|
||||
db 0,3,0,3,6,19,2,34,1,30,0,-12,0,0,-39,-13,-15,1,3
|
||||
db 41,48,2,127,2,0,1,48,2,64,2,80,2,96,2,112,2,127,10,127,2,0,1,48,2,127,2,0,1,48,2,127,2,0,0,48,2,127,2,0,-1
|
||||
; 15: Snare / 07|snare1
|
||||
db 0,5,26,10,10,16,20,4,-2,30,-2,0,-70,0,28,53,-104,-4,1
|
||||
db 55,3,2,4,2,7,2,16,1,17,2,20,2,30,2,32,1,34,2,43,2,47,2,48,1,56,2,57,2,60,2,64,2,64,1,69,2,80,1,82,2,96,2,96,1,112,1,127,2,127,1,0,4,16,2,19,2,22,2,25,2,28,2,31,2,34,2,37,2,40,2,43,2,46,2,50,2,53,2,56,2,59,2,62,2,65,2,68,2,71,2,74,2,77,2,81,2,84,2,87,2,90,1,91,1,92,1,94,1,95,1,97,1,98,1,100,1,101,1,103,1,104,1,106,1,107,1,109,1,110,1,112,5,112,1,0,-1
|
||||
; 16: Hihat / 08|hihat
|
||||
db 0,0,13,23,0,7,12,37,2,30,55,22,0,0,0,6,-59,-6,-19
|
||||
db 68,80,2,127,2,0,-1
|
||||
db -1,-1
|
||||
|
||||
section notepos data align=1
|
||||
|
||||
_NotePositions:
|
||||
; 00: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 0,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1
|
||||
; position 1 - pattern 1
|
||||
db 16,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1
|
||||
; position 4 - pattern 4
|
||||
db -2,16,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2,4,4,2,2
|
||||
; position 5 - pattern 5
|
||||
db 4,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2
|
||||
; position 6 - pattern 6
|
||||
db 16,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1,8,1,1,1,1,1,1,1
|
||||
; position 7 - pattern 7
|
||||
db 1,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,4,6,6,4
|
||||
; position 8 - pattern 8
|
||||
db 64,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2,4,4,2,2
|
||||
; position 9 - pattern 9
|
||||
db 4,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2,4,4,2,2
|
||||
; position 10 - pattern 10
|
||||
db 4,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2,4,4,2,2
|
||||
; position 11 - pattern 11
|
||||
db 4,4,6,6,4,6,6,4,4,2,2,4,4,2,4,2,4,4,6,2,2,2,4,4,2,2,4,4,6,2,2,2
|
||||
|
||||
; 01: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 0,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1
|
||||
; position 1 - pattern 1
|
||||
db 16,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1
|
||||
; position 4 - pattern 4
|
||||
db -2,16,4,6,6,4,6,6,4,6,2,4,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,4,2,4,4,2,2
|
||||
; position 5 - pattern 5
|
||||
db 4,4,2,1,1,2,6,4,6,6,4,6,2,3,1,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,4,2
|
||||
; position 6 - pattern 6
|
||||
db 16,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,8,2,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,2,2,2,2,2,1,1,1,1,8,1,1,1,1,1,1,1
|
||||
; position 7 - pattern 7
|
||||
db 1,6,1,1,13,1,1,1,2,4,5,1,1,1,1,1,1,1,1,1,4,6,6,4
|
||||
; position 8 - pattern 8
|
||||
db 64,4,6,6,4,6,6,4,6,2,4,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,4,2,4,4,2,2
|
||||
; position 9 - pattern 9
|
||||
db 4,4,6,6,4,6,6,4,6,2,4,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,4,2,4,4,2,2
|
||||
; position 10 - pattern 10
|
||||
db 4,4,6,6,4,6,6,4,6,2,4,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,4,2,4,4,2,2
|
||||
; position 11 - pattern 11
|
||||
db 4,4,6,6,4,6,6,4,6,2,4,4,2,4,2,2,2,4,6,4,2,4,4,2,2,4,4,6,2,2,2
|
||||
|
||||
; 02: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 4 - pattern 4
|
||||
db -3,8,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8,8
|
||||
; position 5 - pattern 5
|
||||
db 16,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8
|
||||
; position 8 - pattern 8
|
||||
db -2,24,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8,8
|
||||
; position 9 - pattern 9
|
||||
db 16,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8,8
|
||||
; position 10 - pattern 10
|
||||
db 16,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8,8
|
||||
; position 11 - pattern 11
|
||||
db 16,4,4,6,6,2,4,4,8,2,6,6,4,8,8,8,8,8,8
|
||||
|
||||
; 03: Track 02 / 09|VST: Clinkster (Basic)
|
||||
; position 4 - pattern 4
|
||||
db -3,0,2,4,4,2,2,2,2,4,4,4,6,2,4,4,6,4,4,4,8,4,12,8,4
|
||||
; position 5 - pattern 5
|
||||
db 28,2,4,4,2,2,2,2,4,4,4,6,2,4,4,6,4,4,4,8,4,12,8,4
|
||||
; position 8 - pattern 8
|
||||
db -2,28,10,2,2,2,4,2,6,4,6,6,4,6,6,4
|
||||
; position 9 - pattern 9
|
||||
db 64,10,2,2,2,4,2,6,4,6,6,4,6,6,4
|
||||
; position 10 - pattern 10
|
||||
db 64,10,2,2,2,4,2,6,4,6,6,4,6,6,4
|
||||
; position 11 - pattern 11
|
||||
db 64,10,2,2,2,4,2,6,4,6,6,4,6,6,4
|
||||
|
||||
; 04: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 60
|
||||
; position 1 - pattern 1
|
||||
db -1,128,36
|
||||
; position 3 - pattern 3
|
||||
db -2,0
|
||||
; position 4 - pattern 4
|
||||
db 92
|
||||
; position 6 - pattern 6
|
||||
db -1,196,60
|
||||
; position 7 - pattern 7
|
||||
db 68,60
|
||||
; position 8 - pattern 8
|
||||
db -1,128
|
||||
; position 9 - pattern 9
|
||||
db -1,128
|
||||
; position 10 - pattern 10
|
||||
db 68,60
|
||||
; position 11 - pattern 11
|
||||
db 68,60
|
||||
|
||||
; 05: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 62
|
||||
; position 1 - pattern 1
|
||||
db -1,128,36
|
||||
; position 3 - pattern 3
|
||||
db -2,0
|
||||
; position 4 - pattern 4
|
||||
db 92
|
||||
; position 6 - pattern 6
|
||||
db -1,196,60
|
||||
; position 7 - pattern 7
|
||||
db 68,60
|
||||
; position 8 - pattern 8
|
||||
db -1,128
|
||||
; position 9 - pattern 9
|
||||
db -1,128
|
||||
; position 10 - pattern 10
|
||||
db 68,60
|
||||
; position 11 - pattern 11
|
||||
db 68,60
|
||||
|
||||
; 06: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 1 - pattern 1
|
||||
db -1,232
|
||||
; position 4 - pattern 4
|
||||
db -2,96
|
||||
; position 8 - pattern 8
|
||||
db -3,0
|
||||
; position 9 - pattern 9
|
||||
db -1,128
|
||||
|
||||
; 07: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 0,16,16,16,16
|
||||
; position 1 - pattern 1
|
||||
db 64,16,16,16,16
|
||||
; position 2 - pattern 2
|
||||
db 64,16,16,16,16
|
||||
; position 3 - pattern 3
|
||||
db 64,16,16,16,16
|
||||
; position 4 - pattern 4
|
||||
db 64,16,16,16,16
|
||||
; position 5 - pattern 5
|
||||
db 64,16,16,16,16
|
||||
; position 6 - pattern 6
|
||||
db 64,16,16,16,16
|
||||
; position 7 - pattern 7
|
||||
db 64,16,16,16,6,6,4
|
||||
; position 10 - pattern 10
|
||||
db -2,64,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6
|
||||
; position 11 - pattern 11
|
||||
db 6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6
|
||||
|
||||
; 08: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 0,16,16,64
|
||||
; position 1 - pattern 1
|
||||
db 32,16,16,64
|
||||
; position 2 - pattern 2
|
||||
db 32,16,16,64
|
||||
; position 3 - pattern 3
|
||||
db 32,16,16,64
|
||||
; position 4 - pattern 4
|
||||
db 32,16,16,64
|
||||
; position 5 - pattern 5
|
||||
db 32,16,16,64
|
||||
; position 6 - pattern 6
|
||||
db 32,16,16,64
|
||||
; position 7 - pattern 7
|
||||
db 32,16,16,16,6,6,4
|
||||
; position 10 - pattern 10
|
||||
db -2,64,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6
|
||||
; position 11 - pattern 11
|
||||
db 6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6
|
||||
|
||||
; 09: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 0,16,32
|
||||
; position 1 - pattern 1
|
||||
db 80,16,32
|
||||
; position 2 - pattern 2
|
||||
db 80,16,32,24,8,8,4
|
||||
; position 3 - pattern 3
|
||||
db 36,16,32,24,8,8,4
|
||||
; position 4 - pattern 4
|
||||
db 36,16,32
|
||||
; position 5 - pattern 5
|
||||
db 80,16,32
|
||||
; position 6 - pattern 6
|
||||
db 80,16,32
|
||||
; position 7 - pattern 7
|
||||
db 80,16,32,6,6,4
|
||||
; position 10 - pattern 10
|
||||
db -2,64,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6
|
||||
; position 11 - pattern 11
|
||||
db 6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6,4,6,6
|
||||
|
||||
; 10: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 24,32
|
||||
; position 1 - pattern 1
|
||||
db 96,32
|
||||
; position 2 - pattern 2
|
||||
db 96,32
|
||||
; position 3 - pattern 3
|
||||
db 96,32
|
||||
; position 4 - pattern 4
|
||||
db 96,8,24
|
||||
; position 5 - pattern 5
|
||||
db 96,8,24
|
||||
; position 6 - pattern 6
|
||||
db 96,32
|
||||
; position 7 - pattern 7
|
||||
db 96
|
||||
; position 10 - pattern 10
|
||||
db -2,128,32
|
||||
; position 11 - pattern 11
|
||||
db 96,32
|
||||
|
||||
; 11: Long Bass / 01|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 64
|
||||
; position 1 - pattern 1
|
||||
db 64,16,16,16,16
|
||||
; position 2 - pattern 2
|
||||
db 64,16,16,16,16,32
|
||||
; position 3 - pattern 3
|
||||
db 32,16,16,16,16,32
|
||||
; position 4 - pattern 4
|
||||
db 96
|
||||
; position 5 - pattern 5
|
||||
db -1,128
|
||||
; position 6 - pattern 6
|
||||
db 64,16,16,16,16,32
|
||||
; position 7 - pattern 7
|
||||
db 32,16,16,16,16,32
|
||||
; position 9 - pattern 9
|
||||
db -1,224,32
|
||||
; position 10 - pattern 10
|
||||
db 32,16,16,16,16,32
|
||||
; position 11 - pattern 11
|
||||
db 32,16,16,16,16,32
|
||||
|
||||
; 12: Bassdrum / 02|VST: Clinkster (Basic)
|
||||
; position 2 - pattern 2
|
||||
db -2,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 3 - pattern 3
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 5 - pattern 5
|
||||
db -2,16,13,1
|
||||
; position 6 - pattern 6
|
||||
db 2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 7 - pattern 7
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,6,6,4,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 10 - pattern 10
|
||||
db -2,32,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 11 - pattern 11
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,1,1
|
||||
|
||||
; 13: Zap / 03|VST: Clinkster (Basic)
|
||||
; position 2 - pattern 2
|
||||
db -2,1,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1
|
||||
; position 3 - pattern 3
|
||||
db 3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1,4,3,1,2,1,3,1,1
|
||||
|
||||
; 14: Counter Bass / 05|VST: Clinkster (Basic)
|
||||
; position 1 - pattern 1
|
||||
db -1,130,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 2 - pattern 2
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 3 - pattern 3
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 4 - pattern 4
|
||||
db 36,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 5 - pattern 5
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 6 - pattern 6
|
||||
db 20,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 7 - pattern 7
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 8 - pattern 8
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 9 - pattern 9
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 10 - pattern 10
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 11 - pattern 11
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
|
||||
; 15: Snare / 07|snare1
|
||||
; position 1 - pattern 1
|
||||
db -1,132,8,8,8,8,8,8,8,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 2 - pattern 2
|
||||
db 5,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
|
||||
; position 3 - pattern 3
|
||||
db 8,8,8,8,8,8,8,8,8,8,8,8,4
|
||||
; position 5 - pattern 5
|
||||
db -1,224,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,12,2,1
|
||||
; position 6 - pattern 6
|
||||
db 5,2,6,8,3,2,3,8,8,3,5,2,6,8,3,5,8,3,5,8,8,8,8,1,2
|
||||
; position 7 - pattern 7
|
||||
db 5,2,6,8,3,2,3,8,8,3,1,6,6,4,4,3,5,8,3,5
|
||||
; position 9 - pattern 9
|
||||
db -1,228,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 10 - pattern 10
|
||||
db 5,3,5,8,3,2,3,8,3,5,8,3,2,3,2,1,5,3,5,8,3,2,3,8,3,5,8,3,2,3,2,1
|
||||
; position 11 - pattern 11
|
||||
db 5,3,5,8,3,2,3,8,3,5,8,3,2,3,2,1
|
||||
|
||||
; 16: Hihat / 08|hihat
|
||||
; position 1 - pattern 1
|
||||
db -1,130,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 2 - pattern 2
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 3 - pattern 3
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2
|
||||
; position 5 - pattern 5
|
||||
db -1,162,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 6 - pattern 6
|
||||
db 20,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 7 - pattern 7
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,2,6,6,4
|
||||
; position 8 - pattern 8
|
||||
db 66,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 9 - pattern 9
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 10 - pattern 10
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
; position 11 - pattern 11
|
||||
db 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
|
||||
|
||||
section notesamp data align=1
|
||||
|
||||
_NoteSamples:
|
||||
; 00: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 2,16,24,34,42,32,31,18,6,6,41,33,24,11,7,13,23,14,8,27,37,10,23,36,27,5,27,44,41,29,18,30,40,28,21,29,38,30,19,28,41,43,38,29,20,14,6,31,22,42,31,22,31,22,15,39,29,20,14,6
|
||||
; position 1 - pattern 1
|
||||
db 2,16,24,34,42,32,31,18,6,6,41,33,24,11,7,13,23,14,8,27,37,10,23,36,27,5,27,44,41,29,18,30,40,28,21,29,38,30,19,28,41,43,38,29,20,14,6,31,22,42,31,22,31,22,15,39,29,20,14,6
|
||||
; position 4 - pattern 4
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,1,27,31,15,1,6,1,15
|
||||
; position 5 - pattern 5
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,1,27,31,15
|
||||
; position 6 - pattern 6
|
||||
db 2,16,24,34,42,32,31,18,6,6,41,33,24,11,7,13,23,14,8,27,37,10,23,36,27,5,27,44,41,29,18,30,40,28,21,29,38,30,19,28,41,43,38,29,20,14,6,31,22,42,31,22,31,22,15,39,29,20,14,6,38,35,29,25,21,11,21,12
|
||||
; position 7 - pattern 7
|
||||
db 2,16,24,34,42,32,31,18,6,6,41,33,24,11,7,13,23,14,8,27,17,27,17,22
|
||||
; position 8 - pattern 8
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,1,27,31,15,1,6,1,15
|
||||
; position 9 - pattern 9
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,1,27,31,15,1,6,1,15
|
||||
; position 10 - pattern 10
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,1,27,31,15,1,6,1,15
|
||||
; position 11 - pattern 11
|
||||
db 3,3,3,6,4,4,9,9,5,5,5,27,0,27,0,26,6,1,1,27,31,15,1,6,1,15,6,1,42,31,22,15
|
||||
db -1
|
||||
|
||||
; 01: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 4,20,29,38,46,36,35,23,9,9,45,37,29,15,10,17,28,18,11,31,41,13,28,40,31,7,31,48,45,33,23,34,44,32,26,33,42,34,24,32,45,47,42,33,25,18,9,35,27,46,35,27,35,27,19,43,33,25,18,9
|
||||
; position 1 - pattern 1
|
||||
db 4,20,29,38,46,36,35,23,9,9,45,37,29,15,10,17,28,18,11,31,41,13,28,40,31,7,31,48,45,33,23,34,44,32,26,33,42,34,24,32,45,47,42,33,25,18,9,35,27,46,35,27,35,27,19,43,33,25,18,9
|
||||
; position 4 - pattern 4
|
||||
db 5,22,22,6,9,27,7,31,31,19,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,19,6,9,19,3,35,9
|
||||
; position 5 - pattern 5
|
||||
db 5,22,21,12,5,22,6,9,27,7,31,31,19,8,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,19,6,9
|
||||
; position 6 - pattern 6
|
||||
db 4,20,29,38,46,36,35,23,9,9,45,37,29,15,10,17,28,18,11,31,41,13,28,40,31,7,31,48,45,33,23,34,44,32,26,33,42,34,24,32,45,47,42,33,25,18,9,35,27,46,35,27,35,27,19,43,33,25,18,9,42,39,33,30,26,15,26,16
|
||||
; position 7 - pattern 7
|
||||
db 4,20,29,38,46,36,35,23,9,9,45,37,29,15,10,17,28,18,11,31,14,14,14,19
|
||||
; position 8 - pattern 8
|
||||
db 5,22,22,6,9,27,7,31,31,19,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,19,6,9,19,3,35,9
|
||||
; position 9 - pattern 9
|
||||
db 5,22,22,6,9,27,7,31,31,19,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,19,6,9,19,3,35,9
|
||||
; position 10 - pattern 10
|
||||
db 5,22,22,6,9,27,7,31,31,19,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,19,6,9,19,3,35,9
|
||||
; position 11 - pattern 11
|
||||
db 5,22,22,6,9,27,7,31,31,19,14,14,14,14,19,22,7,19,19,6,9,19,3,35,9,7,19,3,2,1,0
|
||||
db -1
|
||||
|
||||
; 02: Pizzicato Lead / 00|VST: Clinkster (Basic)
|
||||
; position 4 - pattern 4
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,3,2
|
||||
; position 5 - pattern 5
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,3
|
||||
; position 8 - pattern 8
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,3,2
|
||||
; position 9 - pattern 9
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,3,2
|
||||
; position 10 - pattern 10
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,3,2
|
||||
; position 11 - pattern 11
|
||||
db 0,4,12,2,1,3,11,2,8,11,10,7,5,12,12,13,9,6,11
|
||||
db -1
|
||||
|
||||
; 03: Track 02 / 09|VST: Clinkster (Basic)
|
||||
; position 4 - pattern 4
|
||||
db 20,11,19,23,22,18,12,9,6,9,13,12,9,6,13,11,9,6,8,19,16,17,21,17
|
||||
; position 5 - pattern 5
|
||||
db 20,11,19,23,22,18,12,9,6,9,13,12,9,6,13,11,9,6,8,19,16,17,21,17
|
||||
; position 8 - pattern 8
|
||||
db 2,0,1,3,4,1,5,4,5,10,6,13,10,14,7
|
||||
; position 9 - pattern 9
|
||||
db 2,0,1,3,4,1,5,4,5,10,6,13,10,14,15
|
||||
; position 10 - pattern 10
|
||||
db 2,0,1,3,4,1,5,4,5,10,6,13,10,14,7
|
||||
; position 11 - pattern 11
|
||||
db 2,0,1,3,4,1,5,4,5,10,6,13,10,14,15
|
||||
db -1
|
||||
|
||||
; 04: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 1
|
||||
; position 1 - pattern 1
|
||||
db 1,1
|
||||
; position 3 - pattern 3
|
||||
db 0
|
||||
; position 4 - pattern 4
|
||||
db 1
|
||||
; position 6 - pattern 6
|
||||
db 2,1
|
||||
; position 7 - pattern 7
|
||||
db 2,1
|
||||
; position 8 - pattern 8
|
||||
db 1
|
||||
; position 9 - pattern 9
|
||||
db 1
|
||||
; position 10 - pattern 10
|
||||
db 2,1
|
||||
; position 11 - pattern 11
|
||||
db 2,1
|
||||
db -1
|
||||
|
||||
; 05: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 1
|
||||
; position 1 - pattern 1
|
||||
db 1,1
|
||||
; position 3 - pattern 3
|
||||
db 0
|
||||
; position 4 - pattern 4
|
||||
db 1
|
||||
; position 6 - pattern 6
|
||||
db 2,1
|
||||
; position 7 - pattern 7
|
||||
db 2,1
|
||||
; position 8 - pattern 8
|
||||
db 1
|
||||
; position 9 - pattern 9
|
||||
db 1
|
||||
; position 10 - pattern 10
|
||||
db 2,1
|
||||
; position 11 - pattern 11
|
||||
db 2,1
|
||||
db -1
|
||||
|
||||
; 06: Scream / 04|VST: Clinkster (Basic)
|
||||
; position 1 - pattern 1
|
||||
db 1
|
||||
; position 4 - pattern 4
|
||||
db 0
|
||||
; position 8 - pattern 8
|
||||
db 0
|
||||
; position 9 - pattern 9
|
||||
db 0
|
||||
db -1
|
||||
|
||||
; 07: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 15,7,10,16,6
|
||||
; position 1 - pattern 1
|
||||
db 15,7,10,16,4
|
||||
; position 2 - pattern 2
|
||||
db 15,7,10,16,4
|
||||
; position 3 - pattern 3
|
||||
db 15,7,10,16,5
|
||||
; position 4 - pattern 4
|
||||
db 13,3,9,14,1
|
||||
; position 5 - pattern 5
|
||||
db 13,3,9,14,2
|
||||
; position 6 - pattern 6
|
||||
db 15,7,10,16,4
|
||||
; position 7 - pattern 7
|
||||
db 15,7,10,17,12,17,6
|
||||
; position 10 - pattern 10
|
||||
db 17,17,0,8,8,8,11,11,11,17,17,17,8,8,8,8,8,8,8,8,8,8,8,8
|
||||
; position 11 - pattern 11
|
||||
db 17,17,0,8,8,8,11,11,11,17,17,17,8,8,8,8,8,8,8
|
||||
db -1
|
||||
|
||||
; 08: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 7,12,6,2
|
||||
; position 1 - pattern 1
|
||||
db 7,12,6,0
|
||||
; position 2 - pattern 2
|
||||
db 7,12,6,0
|
||||
; position 3 - pattern 3
|
||||
db 7,12,6,1
|
||||
; position 4 - pattern 4
|
||||
db 5,11,4,0
|
||||
; position 5 - pattern 5
|
||||
db 5,11,4,2
|
||||
; position 6 - pattern 6
|
||||
db 7,12,6,0
|
||||
; position 7 - pattern 7
|
||||
db 7,12,7,8,8,8,9
|
||||
; position 10 - pattern 10
|
||||
db 8,8,8,13,13,13,8,8,8,8,8,8,3,3,3,3,3,3,10,10,10,10,10,10
|
||||
; position 11 - pattern 11
|
||||
db 8,8,8,13,13,13,8,8,8,8,8,8,3,3,3,3,3,3,10
|
||||
db -1
|
||||
|
||||
; 09: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 1,4,7
|
||||
; position 1 - pattern 1
|
||||
db 1,4,8
|
||||
; position 2 - pattern 2
|
||||
db 1,4,8,17,16,15,13
|
||||
; position 3 - pattern 3
|
||||
db 1,4,8,17,16,18,19
|
||||
; position 4 - pattern 4
|
||||
db 0,3,6
|
||||
; position 5 - pattern 5
|
||||
db 0,3,6
|
||||
; position 6 - pattern 6
|
||||
db 1,4,8
|
||||
; position 7 - pattern 7
|
||||
db 1,4,9,9,9,12
|
||||
; position 10 - pattern 10
|
||||
db 2,2,11,5,5,5,10,10,10,9,9,9,10,10,10,10,10,10,14,14,14,14,14,14
|
||||
; position 11 - pattern 11
|
||||
db 2,2,11,5,5,5,10,10,10,9,9,9,10,10,10,10,10,10,14
|
||||
db -1
|
||||
|
||||
; 10: Strings / 06|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 7,6
|
||||
; position 1 - pattern 1
|
||||
db 7,4
|
||||
; position 2 - pattern 2
|
||||
db 7,4
|
||||
; position 3 - pattern 3
|
||||
db 7,5
|
||||
; position 4 - pattern 4
|
||||
db 3,2,0
|
||||
; position 5 - pattern 5
|
||||
db 3,2,1
|
||||
; position 6 - pattern 6
|
||||
db 7,4
|
||||
; position 7 - pattern 7
|
||||
db 7
|
||||
; position 10 - pattern 10
|
||||
db 8,4
|
||||
; position 11 - pattern 11
|
||||
db 8,8
|
||||
db -1
|
||||
|
||||
; 11: Long Bass / 01|VST: Clinkster (Basic)
|
||||
; position 0 - pattern 0
|
||||
db 3
|
||||
; position 1 - pattern 1
|
||||
db 7,9,11,1,3
|
||||
; position 2 - pattern 2
|
||||
db 6,8,10,0,2,2
|
||||
; position 3 - pattern 3
|
||||
db 7,9,11,1,4,5
|
||||
; position 4 - pattern 4
|
||||
db 3
|
||||
; position 5 - pattern 5
|
||||
db 3
|
||||
; position 6 - pattern 6
|
||||
db 7,9,11,1,4,4
|
||||
; position 7 - pattern 7
|
||||
db 7,9,11,1,4,4
|
||||
; position 9 - pattern 9
|
||||
db 4,4
|
||||
; position 10 - pattern 10
|
||||
db 7,9,11,1,4,4
|
||||
; position 11 - pattern 11
|
||||
db 7,9,11,1,4,5
|
||||
db -1
|
||||
|
||||
; 12: Bassdrum / 02|VST: Clinkster (Basic)
|
||||
; position 2 - pattern 2
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||
; position 3 - pattern 3
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||
; position 5 - pattern 5
|
||||
db 3,4,3
|
||||
; position 6 - pattern 6
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||
; position 7 - pattern 7
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||
; position 10 - pattern 10
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
|
||||
; position 11 - pattern 11
|
||||
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,3
|
||||
db -1
|
||||
|
||||
; 13: Zap / 03|VST: Clinkster (Basic)
|
||||
; position 2 - pattern 2
|
||||
db 5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1
|
||||
; position 3 - pattern 3
|
||||
db 5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2,0,4,2,3,1,5,4,2
|
||||
db -1
|
||||
|
||||
; 14: Counter Bass / 05|VST: Clinkster (Basic)
|
||||
; position 1 - pattern 1
|
||||
db 10,10,10,10,12,12,12,12,14,14,14,14,1,1,1,1,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
|
||||
; position 2 - pattern 2
|
||||
db 10,10,10,10,12,12,12,12,14,14,14,14,1,1,1,1,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
|
||||
; position 3 - pattern 3
|
||||
db 10,10,10,10,12,12,12,12,14,14,14,14,1,1,1,1,8,8,8,8,8,8,8,7
|
||||
; position 4 - pattern 4
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||
; position 5 - pattern 5
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2
|
||||
; position 6 - pattern 6
|
||||
db 10,10,10,10,12,12,12,12,14,14,14,14,1,1,1,1,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
|
||||
; position 7 - pattern 7
|
||||
db 10,10,10,10,12,12,12,12,14,14,14,14,1,1,1,1,8,8,8,8,8,8,8,8,6,5,4,3,2,2,2,2
|
||||
; position 8 - pattern 8
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||
; position 9 - pattern 9
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||
; position 10 - pattern 10
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
|
||||
; position 11 - pattern 11
|
||||
db 9,9,9,9,11,11,11,11,13,13,13,13,0,0,0,0,2,2,2,2,2,2,2,2
|
||||
db -1
|
||||
|
||||
; 15: Snare / 07|snare1
|
||||
; position 1 - pattern 1
|
||||
db 3,3,7,7,11,11,16,16,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64
|
||||
; position 2 - pattern 2
|
||||
db 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24
|
||||
; position 3 - pattern 3
|
||||
db 24,24,24,24,24,24,24,24,24,24,24,24,24
|
||||
; position 5 - pattern 5
|
||||
db 1,0,4,2,6,5,9,8,12,10,17,14,19,13,20,15,24,18,24,18,24,18,24,18,24,18,24,18,24,18,24,21,24,23,24,22
|
||||
; position 6 - pattern 6
|
||||
db 24,7,24,24,7,7,24,24,24,7,24,7,24,24,7,24,24,7,24,24,24,24,24,18,18
|
||||
; position 7 - pattern 7
|
||||
db 24,7,24,24,7,7,24,24,24,7,24,24,24,24,24,7,24,24,7,24
|
||||
; position 9 - pattern 9
|
||||
db 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,65
|
||||
; position 10 - pattern 10
|
||||
db 24,18,24,24,18,16,24,24,16,24,24,18,18,24,18,16,24,18,24,24,18,16,24,24,16,24,24,18,18,24,18,16
|
||||
; position 11 - pattern 11
|
||||
db 24,18,24,24,18,16,24,24,16,24,24,18,18,24,18,16
|
||||
db -1
|
||||
|
||||
; 16: Hihat / 08|hihat
|
||||
; position 1 - pattern 1
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 2 - pattern 2
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 3 - pattern 3
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 5 - pattern 5
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 6 - pattern 6
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 7 - pattern 7
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 8 - pattern 8
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
; position 9 - pattern 9
|
||||
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
; position 10 - pattern 10
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
; position 11 - pattern 11
|
||||
db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
db -1
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
Player source code and usage example.
|
||||
|
||||
In order to build, you need to set up a rule in Visual Studio to compile
|
||||
.asm files. I can recommend Yasm, which has nice Visual Studio integration
|
||||
plus debugging support, but Nasm works as well.
|
Loading…
Reference in New Issue