Chapter 14 - Additional information



Here is a summary of Bhajis Loops shortcuts:

Arrange window

N New song
O Open song
S Save song
M Import MIDIfile
Z Undo
X Cut
C Copy
V Paste
A Select all
D Delete bar
I Insert bar
B Go to beginning of song
E Go to end of song
1 Go to loop start
2 Go to loop end
R Go to locator
G Display the position dialog
0 Disable looping


Pattern editor

Y Pattern library
R Record
H Chords
T Ternarize
Z Undo
X Cut
C Copy
V Paste
L Paste in place
D Delete
A Select all
I Instrument remap
K Toggle pattern break
S Cycle instrument group
M Enable instrument mask
0 Disable instrument mask

Instrument editor

D Default settings
O Open instrument
S Save instrument
P Voices / Polyphony
K Keyboard mapping
L Layering
T Transpose
C Copy
V Paste

Sample editor

I Sample Information
O Open sample
R Record
D Delete sample
H Move sample to dynamic heap
S Move sample to storage heap
M Add several samples

Live mode

O Open song
X Exit live! mode



O Open song
S Save song
M Toggle master section
A Automation view
X XY Pad



O Open song
S Save song
Z Undo
X Cut
C Copy
V Paste
A Select all
F Simplify
W Smooth
T Transform
D Delete track
Zoom level (1, 2, 4, 8 and 16 bars)
M Mixer view
P XY Pad


The Internals dialog

While you are in the arrange window and while a song is playing, you can display this hidden dialog by entering in the graffiti area the stroke for the letter G. This dialog displays the following information:

You can press the Reset max button to reset the maximum values displayed.

The Dump voicelist to card function dumps the voices data structure to a file named voices.bin at the root directory of the first memory card available. If you experience very weird things and think you have found a bug in the playing engine, this file can help me to identify the problem.


How to crack Bhajis Loops?

Little bastard!

Note: The patch available on a famous WareZ site is poorly done and does not fully unlock the application.


Developing your own plugins or using Bhajis Loops plugins in your own music application

Resource database layout

Basically, a plug-in is a resource database (type: Plug, creator: AudX) with the following resources:

type: arml, id: 1. ARM Initialization code. A pointer to this code is passed to PceNativeCall when the plug-in is loaded. You should initialize look-up tables and buffers there.

type: arml, id: 2. ARM Cleanup code. This code is called whenever you stop playing, and the first time you start playing. You should reinitialize state variables or clean buffers there.

type: arml, id: 3. ARM Render code. This code is called whenever the content of a buffer is to be rendered.

type: tSTR, id: 8533. (Optional) string of the plug-in Help dialog.

type: name, id: 1000. Plug-in name.

type: info, id: 1000. A string containing credits, copyright, or other information. Typically displayed in the "about this plug-in" dialog.

type: data, id: 1000. 4 16-bit words in motorola byte order (UInt16), indicating the size (up to 64kb) of the 4 data buffers required by the plug-in (for example, for delay lines). Must be 0 if no data is required.

type: prms, id: 1000: one char indicating the number of parameters (up to 32 parameters can be used) ; then, for each parameter, its name (zero terminated string), and 3 motorola-ordered, signed 16-bit integers indicating the minimal, maximal and default value of the parameter.

type: insr, id: 1000 : one char, equal to zero if the plug-in works in "send" mode ; one if it works in "insert" mode. Ideally, the output of a plug-in must be mixed with the original signal according to the following formulae:

Source code

Ideally, plug-ins should also be provided as Windows dll (same name as the plug-in database name), to allow the rendering of songs during hotsync.

You can refer to the source code of the delay plug-in for more information.


BJM file format specifications

When not specified, strings are zero terminated. Boolean are: 0 = false ; 255 = true. Values different from 255 for True might lead to unpredictable results.

When not specified, integers are intel ordered (some parts of Bhajis Loops are written for ARM, some others for 68k, so the two format are used).

To deal with the evolution of the file format, most of the important sections start with a format ID byte, so that it is possible to identify which version of the program has been used to write the section, and skip / alter the data when needed.


The bjm format

byte: song format ID (From 1 to 10).
string: song format string ; must be equal to "Recipe for pure veg song
string: song title
string: song information
boolean: true if the song info dialog should be displayed whenever the song
is opened.
byte: beginning of loop
byte: end of loop (the loop markers in the arrange window)
intel short: number of steps per pattern (from 1 to 32)
intel short: shuffle (0 to 127). 0 = 1 1 1 1 1 1 1 1. 127 = 1.5 1.5 0.5 0.5
1.5 1.5 0.5 0.5 (relative durations)

if format >=4
 boolean: true when ternary /8 signatures must be used
 if format >=7 byte: number of beats per tap for the tap tempo function
 byte: key (0: C, 1: C#, 2: D...)
 byte: mode (0: major, 1: minor, 2: harmonic minor, 3..5: pentatonic, 6: dorian, 7: lydian, 8: mixolydian)
end if

if format >= 9
 byte[12]: for each note (C, C#, D...) index of the corresponding item in the "Advanced tuning" dialog
 motorola double[12]: for each note, frequency ratio to 261Hz C, as a double precision float.
 motorola short[12]: for each note, frequency ratio to 261Hz C, numerator.
 motorola short[12]: for each note, frequency ratio to 261Hz C, denominator.
 equally tempered scale must be used.

motorola long: BPM
char[SONGLENGTH * TRACKS]: song matrix (TRACKS = 8, SONGLENGTH 248).

if format >= 2
 two [[BUS]] sections (one for each effect bus)
end if

if format >= 9
 two extra [[BUS]] sections (one for each effect bus)
end if

if format >= 6 one [[BUS]] section (for the main effect bus)

if format >=5
 intel short: master level L
 intel short: master level R
 boolean: continue
 while continue
   boolean: continue
end if

if format >= 3
 motorola short: number NN of cues to read
 NN [[CUE]] sections
 5 [[CONTROLLER]] sections
end if

if format >= 10
 6 [[SCENES]] sections
end if

128 [[PATTERN]] sections
motorola short: number N of samples to read
N [[SAMPLE]] sections

if format < 9
 32 [[INSTRUMENT]] sections
 64 [[INSTRUMENT]] sections
end if

if format >= 8
 motorola short: number of section warps
 J [[WARP]] sections
end if

Details of a [[BUS]] section

byte: bus format ID (must be 1)
short: return level
short: insert (=255 for insert effects ; =0 for other effects)
boolean: true if a plug-in is affected affected ; false otherwise

if plug-in affected
 string: plug-in name
 short[32]: plug-in params
end if


Details of a [[PATTERN]] section

byte: pattern format ID (must be 1)
motorola long: pattern color
string: pattern name
motorola short: note count
if note count <> 0
 motorola short: size of notes array (>= note count)
 char[NOTE_ARGUMENTS * size of notes array]: pattern data

 pattern data is stored as following:
 '0 note start (0 to 255, in steps)
 '1 note end (0 to 255, in steps)
 '2 note (standard MIDI note #)
 '3 instrument used (1 to 64)
 '4 velocity (0 to 127)
 '5 pan (0 to 127)
 '6 sample playback offset (0 = sample start / 127 = sample end)
 '7 note cutoff (0 to 127)
 '8 vibrato rate .
 '9 vibrato depth
 '10 note pre-delay (0 = at this step ; 127 = at the next step)
 '11 = 0 for normal notes ; = 255 to indicate that the note is a "pattern break"
 '12 portamento rate.
 '13 (reserved)
 '14 (reserved)
 '15 (reserved)
end if


Details of a [[SAMPLE]] section

byte: sample format ID (1 to 6)
byte: bit depth (8 or 16)
if format = 4, byte: number of channels
motorola long: sample rate
motorola long: sample duration in frames
long: loop start
long: loop end
if format = 1, these values must be divided by 16384
if format = 2, these values must be divided by 8192
if format = 3, these values are expressed in frames and nothing has to be changed.
string: sample name
if format >= 5
if format >= 6, boolean : magic (you don't have to worry about it)
 byte: recommended program change
 byte: recommended key
 byte: recommended pitch
end if
motorola long: sample size S in bytes
char[S]: sample data


Details of an [[INSTRUMENT]] section

byte: instrument format ID (1 to 10)
short: filter order for the LP filter (0 to 3)
if format >= 9, short: filter order for the HP filter (0 to 3)
short: filter cutoff (0 to 512)
short: filter resonance (0 to 127 ; values > 120 should not be used because of self oscillation)
if format >= 2
 short: env. attack
 short: env. decay
 short: env. sustain
 short: env. release
 short: env. decay
 short: env. attack
 (sustain is 0, release is 2048)
end if
short: 1 if envelope affects volume ; 0 otherwise
short: filter envelope rate.
if format >= 6
 short: instrument volume (0 to 16384).
 short: instrument volume (0 to 1024).
end if
if format >= 6
 short: instrument pan (0 to 16384).
 short: instrument pan (0 to 63).
end if

short: instrument pitch reference (MIDI note).
if format >= 3
 short: finetune
end if
short: front cut (0 to 511)
short: vibrato rate (0 to 31)
short: vibrato depth (0 to 127)
if format >= 9 short: growl depth (0 to 127)
if format >= 4 and format < 9
 short: bus number (0, 1 or 2)
 short: send level
end if
if format >= 9
  short: send level for bus 1
  short: send level for bus 2
  short: send level for bus 3
  short: send level for bus 4
end if
if format >= 5
 byte: MidiChannel
 byte: MidiNote
 if format >= 7 byte: MidiProgram
 boolean: MustExtractSampleWhenRendering
 boolean: MustRenderWholeTrackWhenRendering
end if

if format >=8: byte: voice affectation flag (binary value Z0000XXX, Z is set if "no note off" is activated, XXX is the voice affectation mode ; 0 for Pad, 1 for Poly, 2 for Mono, 3 for Legato, 4 for group).

if format >= 9
 boolean: mute
 boolean: solo
 byte: index of the slave instrument
 if format >= 10
  byte: lower note
  byte: upper note
  boolean: instrument does not take the pitch in account

motorola long: instrument color
string: instrument name


Details of a [[CUE]] section

byte: CUE section format ID, equal to 1 or 2.
byte: start point (bars)
byte: end point (bars)
if format >= 2, motorola long: color
string: cue name


Details of a [[CONTROLLERS]] section

byte: target. (1-64: instruments ; 65-68: plug-ins, 255: master section)
byte: parameter.

For plug-ins: the parameter is either the # of the plugin parameter, ranging from 1 to 32, or 33 to control the plug-in return level ;

For instruments, refer to this list:
"Volume", 0
"Pan", 1
"Filter cutoff", 2
"Filter resonance", 3
"Attack", 4
"Decay", 5
"Sustain", 6
"Release", 7
"Env. filter mod", 8
"Env. amp. mod", 9
"Front cut", 10
"Vibrato rate", 11
"Vibrato depth", 12
"Pitch (root note)", 13
"Pitch bend", 14
"Effect Send 1", 15
"Effect Send 2", 16
"Effect Send 3", 17
"Effect Send 4", 18
"Growl depth", 19

For master section: 0 = global master volume (L / R joint), 1 = master volume L, 2 = master volume R, 3 = tempo.


Details of a [[SCENE]] section

Two [[CONTROLLERS]] sections (one for the X axis, one for the Y axis)
motorolla double: value of the Glide parameter.
motorolla double: value of the Speed parameter.
byte: selected tracking mode (0: no tracking, 1: tracking, 2: tracking and smoothing).


Details of an [[AUTOMATION TRACK]] section

byte: automation track format ID (equal to 1)
byte: target. (1-64: instruments ; 65-68: plug-ins, 255: master section)
byte: parameter. (the same convention as for the [[CONTROLLERS]] section is used).
boolean: has more breakpoints?
while has more breakpoints
 boolean: has more breakpoints?


Details of a [[BREAKPOINT]] section

byte: breakpoint format ID (equal to 1)
byte: x (bar)
byte: x (step)
byte: y


Details of a [[WARP]] section

byte: Start section #
byte: Start bar #
byte: End section #
byte: End bar #


All contents and code © Olivier Gillet 2003-2006 - ol dot gillet at gmail dot com

Index - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14