Archive for the ‘Uncategorized’ Category

More on configuring MIDIsport 8×8/s MIDI ports

Saturday, January 9th, 2021

Further to Configuring MIDIsport 8×8/s MIDI ports using a Windows 2000 VM, I’ve found the software/hardware communication to be very flaky, but I’d read that this was always the case.

After some failures, I found that trying to change port mappings and immediately use the hardware didn’t work for me while connected to the PC, using only external MIDI devices at least — the mappings didn’t seem to change and the unit wasn’t showing any activity.

Important: Note that I’m mainly using the MIDIsport 8×8/s as a standalone device with USB mode permanently selected on the front panel, and using a VM per the above post to configure its MIDI port mapping. I haven’t yet tried using it in conjunction with a DAW since getting port mapping to work.

Key point of this post, for standalone usage:

Shut down the VM after configuring and sending mappings to the MIDIsport, and disconnect the USB cable from the MIDIsport. It should then show LED activity with the current mapping after a few seconds (5-10 in my case).

Workflow

So far, my workflow to change ports appears to be this:

1) With MIDIsport 8×8/s running and connected to the PC, run the virtual machine;
2) Once up and running, take over the MIDIsport USB connection through the VM as per the earlier post;
3) Configure the ports as you wish via the Remote software;
4) Send the port configuration to the device (see below);
5) Exit the Remote software and SHUT DOWN THE VM;
6) For standalone use, disconnect the MIDIsport’s USB cable from the PC and wait 5-10 seconds for its LEDs to update*.

* Note that I haven’t yet tried to use with a DAW at this point, so not sure how that would work.

Regarding item 4), I don’t believe the port mappings are saved until you manually send them to the device, like so:

As far as setting up the ports go, it’s a bit of a mind-bender, but you are basically saying that for each of the physical MIDI Out ports, you want to receive data from the selected MIDI In ports only:

(Click for full-size image.)

In the above example, viewing the hardware itself, I have 3 physical MIDI inputs (highlighted in purple) and 5 MIDI outputs (highlighted in red) — please ignore the cable plugged into MIDI OUT 7 here!

For OUT 1 in the software, highlighted in amber in both hardware and software photos, I have selected the 3 MIDI Ins — so MIDI Out port 1 will receive input from my 3 controller devices plugged into MIDI IN 1, 2 and 3.

Compare the hardware and software images to understand how all 3 MIDI Ins are routed to physical MIDI Out port 1.

Once you ‘get’ this, the same has been repeated here for all 5 outputs — so each output MIDI device will receive input from all 3 input MIDI devices.

You can of course adjust to suit your setup, eg. you may only want MIDI Output 5 (let’s say this is a simple synth) to receive input from your master keyboard, connected to MIDI Input 1; in this case you would select only IN 1 against the OUT 5 line.

It’s important to note (this is where it really starts to blow one’s mind) that the port numbers are not MIDI channel numbers! This all affects the physical connections only — the device plugged into MIDI In 1, for example, may have MIDI channel 5 selected.

As long as the physical cables between the input device on channel 5 and the output device on channel 5 are mapped to ‘see’ each other, channel selection just works as normal.

Note that the MIDIsport 8×8/s can save 8 separate mappings, under “Current Patchbay Program” — this is program 1.

Note also that you can store your current mappings by clicking Save and inputting a name for the mapping. I believe to load you would hit Load, select a saved mapping, then Select Hardware to send the mapping to the device, per ‘Workflow’ item 4, above).

You select the programs on the hardware by holding the MIDI Reset button for a second; this shows the current selection by lighting all LEDs except the current program. (The current program will be unlit.)

Holding for longer will cycle through the programs, 1 to 8; keep it held until your desired program is unlit, then release.

Finally, as noted, once you’ve changed your mappings and sent to the device (per ‘Workflow’ item 4, above), shut down the VM to give USB control back to the main PC, and disconnect the USB cable from the MIDIsport. (Again, I have only explored standalone operation, so not yet sure how/if it works with a DAW… though it should.)

I did get into an odd state at one point, whereby attempting to reconnect the MIDIsport to the VM kept dropping the USB connection — my only solution was to reboot the host PC and MIDIsport. Make sure the MIDIsport is up and running before re-running the VM and connecting to the MIDIsport. Also note that the MIDIsport is notorious for needing to be running before external MIDI devices connect to it, so you may need to restart everything!

However, once you have set up a mapping that works, in most cases you probably won’t need to use the VM — just jump through the above hoops if you need to change the mapping.

After that, it should just work standalone with USB mode selected on the front panel and the USB cable disconnected. Make sure you’ve selected the right program number on the MIDIsport, as per the process above. It should be the one you edited in the software!

In short:

1) MIDIsport running first;
2) Run VM;
3) Configure ports;
4) SEND config to MIDIsport;
5) SHUT DOWN VM;
6) Disconnect MIDIsport’s USB cable;
7) MIDIsport should then work as a standalone device!

Items 4 and 5 are important after each remapping — it probably won’t work until you do this.

Again, my use case is currently running external devices/DAW-less only!

Configuring MIDIsport 8×8/s MIDI ports using a Windows 2000 VM

Saturday, January 9th, 2021

This is a quick list of steps needed to gain access to the MIDIsport 8×8/s MIDI port mapping software, only available for Windows 9x/XP/2000.

This post assumes some familiarity with installing and using virtual machines; in my case, I’m using VirtualBox.

No guarantees this will work — I just wrote the steps quickly after getting it going!

The software will run on later versions of Windows, but won’t find the hardware due to different USB driver systems on Windows beyond XP.

You therefore need to use a virtual machine running an earlier OS, which can then access the MIDIsport directly via USB using the original drivers (at least in VirtualBox).

Download MS8x8_1010_web.exe from:

https://www.driverguide.com/driver/detail.php?driverid=211822

On that page, click the link I’ve highlighted in red here:

Click on Filename
Click Download the Driver File only
Complete Captcha
Click Continue
File should download

Install Windows 2000 in VirtualBox — this is something you’ll need to look into if not familiar, as it’s too detailed to go into here.

A suitable copy is available at:

https://archive.org/details/Windows2000ProfessionalSP4

You only need “Windows 2000 (no product key needed).iso” from the ISO files section, or via the torrent.

Click the ISO Image link then “Windows 2000 (no product key needed).iso”.

In the VM settings, enable Drag and Drop (use the Bidirectional option) under General -> Advanced tab.

Make sure USB 1.1 is enabled under USB. (I suggest using 1.1, not later.)

Install Windows 2000 in the virtual machine.

Once installed and running, drag and drop MS8x8_1010_web.exe onto the Windows 2000 desktop.

Shut down Windows 2000.

Turn on the Midisport 8×8/s; if it’s already on, turn it off and back on (important!). Note that I assume here its drivers are already installed in the host OS.

Make sure the Midisport is not being used by the host computer (eg. in a running DAW).

Start Windows 2000 VM.

Run MS8x8_1010_web from the virtual machine’s desktop to install the Midisport USB drivers and MIDIsport 8×8 Remote Panel software.

Select the Devices menu -> USB and then select the Midisport8x8 option to allow it to connect to the VM. (Note that this makes it inaccessible to the host computer, so the VM can take control directly.)

You can now run the Remote software via Start Menu -> Programs -> M-Audio Midisport 8×8 -> MIDIsport 8×8 Remote Panel.

If all went well… woo! Configure your ports!

See also my follow-up post on using the software/hardware setup, which is rather flaky, but apparently always was. You only need the VM to configure the port mapping anyway; the mapping(s) will be saved in the hardware once done.

More on configuring MIDIsport 8×8/s MIDI ports.

Yamaha RY30 Rhythm Programmer: drum machine battery replacement

Sunday, December 20th, 2020

Faced with the now-common !CHANGE BATTERY! message on its display, I recently had to replace the battery in an RY30 drum machine I’d bought.

Having read a few posts on the subject, I decided I was reasonably confident of being able to do the swap, the hardest part of which involves de-soldering and soldering-in a new CR2032 coin-type battery — the type with tabs already fitted (you can’t just remove the existing battery as it’s not in a separate holder).

If you have even the most basic of soldering experience, this should be very straightforward… but do it at your own risk.

I have very little experience of soldering, and couldn’t find any decent pictures of the mainboard online, so I opened up the machine via a set of simple cross-head screws around the edge and rear, easily removed with a normal Phillips-type screwdriver, in order to take a look:

After removing all of the external screws, I carefully lifted off the top half of the case:

Note that the upper board is still attached by two cables, so you can’t move it far.

The cables’ sockets, with cables removed, are highlighted here:

Unplug the two cables from the mainboard and remove the top half.

I only have enough knowledge to be dangerous, so I was very wary of touching the capacitors, making it a little fiddly in terms of access, and the larger plug is made of a very flexible plastic, so it bends readily.

However, with a combination of flat screwdriver edges and swearing, both cables came free without too much trouble.

Here’s the underside of the upper board, showing the other end of the two cables. Note the underside of the jogwheel on the left, just out of interest.

With the rear of the unit facing away from you, the battery is located at the lower-right of the board (that round yellow thing!), and is secured by means of two legs soldered into the board.

Remove the seven brass screws holding the mainboard to the base of the unit:

Be careful with the one at the top right, inside the black data-card shield — try not to drop the screw inside!

Carefully slide the board towards you and it should come free — note that it is still attached by further cables, but this gives just enough access to replace the battery.

There’s nothing to stop you removing the remaining cables if you want better access, but do take some photos first!

I would suggest doing as I did, and giving the board and lower base a sweep with a soft camera brush if you have one, just to remove any dust that has accumulated over the past three decades!

With a soldering iron heated up to full operating temperature, I touched the base of each leg on the underside of the circuit board to melt the solder and they easily came free.

You can see the two large solder pads underneath the mainboard here, with plenty of space around them for the clumsy:

Here’s the board with battery removed:

My photos run out here, as I had to wait days for the battery to arrive, but refitting them was a case of adjusting the legs of the new battery holder so that they were reasonably ready for the pads, applying heat from the top and bottom of each hole.

With the first leg in approximately the right place, heating the underside of the pad for a few seconds allowed the leg to fall through easily; the same for the other leg. (Note that you should avoid heating the board for too long, and that the heat will spread along the circuit traces, so other areas can become very hot!)

Make sure you have the battery the right way round!

When I went to apply solder to the pads underneath, I found that the existing solder had already secured the battery in place and so frankly didn’t bother!

You may need to apply some solder to each underside pad, heating up the solder pad/leg and then simply touching the solder wire to it to get a small amount in place. Do one at a time, letting the first leg cool a little before continuing.

I re-fitted the two cables I unplugged earlier (they only fit one way — there is a slight indent on each so they should go in easily if inserted the right way round).

I connected the power supply up at this point and tested the display, also performing a factory reset: to do this, hold Dec, Pattern and PERC2 (L), then hit Stop/Continue at the prompt. This will clear all patterns and user data, leaving only the original manufacturer data in place.

The !CHANGE BATTERY! message should no longer appear, but any such problems may mean starting over, removing the two cables and perhaps turning the battery around, but it all went very smoothly for me.

Assuming no errors, screw the mainboard back in place. Here’s the earlier picture highlighting the brass screw locations:

Again, be careful with the screw at the top right, inside the black data-card shield — try not to drop it inside!

Note that it’s probably just as easy to solder in a CR2032 coin battery holder so you can more easily replace the battery in future… but I’d waited long enough and wanted to get it finished!

More photos

Hopefully these photos will start to appear in search results over time. Here are a few more that may be of more general use to anyone searching for inside shots of the Yamaha RY30 Rhythm Programmer…


The view inside with the upper and lower boards still connected.


The underside of the mainboard.


Mainboard unscrewed #1.


Mainboard unscrewed #2.


Underside of the upper board (holding the user controls). The underside of the twelve drum pads are visible to the top, jogwheel to the left.


Mainboard removed from the base.


CR2032 battery close-up.

Getting started with mojo3d: Something to see!

Tuesday, February 19th, 2019

Following on from the first part of this tutorial, where we created an empty scene (with nothing of interest to look at), we’ll now add a simple cube.


#Import "<std>"
#Import "<mojo>"
#Import "<mojo3d>"

Using std..
Using mojo..
Using mojo3d..

Class MyGame Extends Window
	
	Field scene:Scene
	Field camera:Camera
	
	Field cube:Model
	
	Method New  (title:String = "My Game", width:Int = 640, height:Int = 480, flags:WindowFlags = WindowFlags.Resizable)
		Super.New (title, width, height, flags)
	End
	
	Method OnCreateWindow () Override
		
		scene						= New Scene
		camera						= New Camera (Self)
		
		Local cube_box:Boxf			= New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
		Local cube_mat:PbrMaterial	= New PbrMaterial (Color.White)
		
		cube						= Model.CreateBox (cube_box, 1, 1, 1, cube_mat)
	
	End
	
	Method OnRender (canvas:Canvas) Override

		If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
		
		RequestRender ()
		
		scene.Update ()
		camera.Render (canvas)
		
	End
	
End

Function Main ()

	New AppInstance
	New MyGame
	
	App.Run ()
	
End

This code adds a field, cube:Model, which we’ll use to store a Model-type entity (a 3D entity with a mesh and other related features).

The cube setup (in OnCreateWindow, after the scene and camera setup) consists of three lines:

  1. Local cube_box:Boxf = New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)

    This creates a Box object (specifically of floating-point type, as denoted by the ‘f’), used to define a volume. The values define the far corners of the box — view these as two lots of three x, y, z values, each set of three defining an offset in space, so -0.5 in each direction, following by 0.5 in each direction, forming two corners into which the box will fit.

  2. Local cube_mat:PbrMaterial = New PbrMaterial (Color.White)

    This line creates a material that will be applied to the cube. (PBR refers to a form of realistic rendering that we won’t go into here.) The PbrMaterial New method can take a colour parameter, and we’re using one of mojo’s built-in Color-class definitions.

  3. cube = Model.CreateBox (cube_box, 1, 1, 1, cube_mat)

    And finally, the CreateBox helper method provided by the Model class takes the box we just set up, uses 1 for each of the x, y, z segment values (how many times the box is split along each axis) and the material to be applied.

Run the code and… nothing appears!

That’s because the camera and the cube occupy the same point in space; we can’t see anything because the inside faces of the cube (normally viewed from outside) are hidden by default.

Add another line after the CreateBox line:

cube.Move (0, 0, 5)

This moves the cube 5 units along the z-axis, into the screen.

Run the code and the cube will appear.

Finally, for a bit of interest, add this line as the first line within OnRender:

cube.Rotate (1, 2, 4)

Run again and the cube will rotate, 1 degree around the x-axis per update, 2 around the y-axis and 4 around the z.

Experiment with the code — change the material colour to another defined in the Color class (see docs, but examples include Color.Red, Color.Lime, etc); also, change the speed of rotation, or set two axes to 0 to see the effect.

You can also change the size of the box definition to scale the cube.

Try moving the camera backwards instead of moving the cube forwards — hint: both Camera and Model are derived from the Entity class, which supplies the Move method. You’ll need to replace the reference to the cube with the reference to the camera, and supply a negative z-value in place of the 5 in order to move the camera back. (If you already know how to check for keypresses, try moving the camera back and forth in OnRender!)

You can download the source code for this tutorial at GitHub. This post is covered by the example, “2. Hello, Stuff.monkey2”.

Getting started with mojo3d: Creating a scene!

Thursday, February 14th, 2019

This is a quick introduction to getting started with mojo3d.

You can download the source code for this tutorial at GitHub; if you don’t know how to use git, just click the big green Clone or download button and select Download ZIP. (You’ll also find a second source file, intended to form part of the next tutorial, that I’ve included in error, but what the hey! It may allow you to move on sooner anyway!)

It assumes you are comfortable with at least the basics of object-oriented programming, working with classes, fields, methods, and the like, but no more than that.

Here’s a simple program that implements just about the minimum necessary for a basic mojo3d application:

#Import "<std>"
#Import "<mojo>"
#Import "<mojo3d>"

Using std..
Using mojo..
Using mojo3d..

Class MyGame Extends Window
	
	Field scene:Scene
	Field camera:Camera
	
	Method New  (title:String = "My Game", width:Int = 640, height:Int = 480, flags:WindowFlags = WindowFlags.Resizable)
		Super.New (title, width, height, flags)
	End
	
	Method OnCreateWindow () Override
		
		scene				= New Scene
		camera				= New Camera (Self)
		
	End
	
	Method OnRender (canvas:Canvas) Override
		
		If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
		
		RequestRender ()
		
		scene.Update ()
		camera.Render (canvas)
		
	End
	
End

Function Main ()

	New AppInstance
	New MyGame
	
	App.Run ()
	
End

Imports

We start with a few imports — the standard library, the mojo graphics library, and the mojo3d library that sits ‘on top’ of mojo.

You will always need to import these three classes at a minimum.

We also specify that we are Using them, in order to avoid the need to prefix all class names; for instance, we can now use Camera instead of mojo3d.Camera.

Main Window class

Next, we create a new class that Extends mojo’s Window class, allowing us to implement our own functionality, and add more as needed, which includes a few fields and three methods: New, OnCreateWindow and OnRender. (Note that MyGame can be called whatever you like, and contains all of the features of the Window class.)

There are two fields present here, scene (of mojo3d’s Scene type) and camera (of mojo3d’s Camera type). These will be the minimum needed in order to create a technically working 3D environment.

The New method simply creates the game window, via the Window.New method (called via Super to refer to the ‘parent’ New method).

OnCreateWindow overrides the parent Window method and implements our required functionality, in this case assigning a new Scene to the scene field, and a Camera to the camera field.

The Scene class organises and manages the entire 3D world, including all entities (3D objects of the Entity class, of which more later).

The Camera class is a built-in class providing visibility into the 3D world. Cameras are a type of Entity class, too, which allows us to move them around, rotate them, etc, like any other 3D object.

OnRender is the final built-in class here, and is where the action takes place.

Here, we check for the Escape key being hit, in which case the application terminates.

We ask the application to update its view via RequestRender — this is required.

We call scene.Update in order to update the scene; this has no effect in this case, but later on it will become relevant and I would suggest adding it anyway. (It will handle physics and collision updates, among other things.)

Finally, we use the camera to render to a canvas. Note that the canvas reference is passed in automatically by mojo (see the OnRender parameter). Rendering to this canvas will result in our 3D view appearing on screen.

Main

The remainder of the code is the standard, required, Main function: it creates a new Application instance, creates a MyGame instance (our overridden Window class) and then runs the application.

Behold!

Run the code, and… oh! It’s a blue screen…

This is fine — we haven’t placed any entities into the scene yet, but this blue is the default Scene screen-clearing colour. (You can modify this using scene.ClearColor = Color.Black, or any of the other built-in colours — to see these, use the Color documentation by placing the cursor inside Color and hitting the F1 key twice. You can of course create your own colours, but we’ll keep things simple for now.)

The blue screen in fact shows that our scene is rendering correctly.

Next time, we’ll add something to look at! (See the GitHub note at the very start if you want to toy with the second source file in the meantime.)

Monkeying Around with mojo3d: Behaviours for simple entity management

Tuesday, January 8th, 2019

Following on from my last post, I am going to cover the final piece of the demo, the white self-deleting markers left by bullets striking the ground:

The source code zip file is in the previous post (scroll down a little), and remains unchanged. I just wanted to separate this out so you can see how useful it is to control non-physics entities too, in a really simple form.

WebGL Demo

Here’s the link to the web demo from that post — this new post relates to the little white markers left when bullets hit the scenery and how they simply remove themselves after a second:

Island WebGL Demo

As before, use Cursors to move, A & Z to speed up/slow down, plus Space to fire. Additionally, the plane now has yaw control, which is controlled via Q and E.

Behaviours, without physics

These ground markers are again defined as Behaviours, but this time without any physics elements — no rigid bodies or colliders this time!

As well as providing an easy way to attach physics to entities, Behaviours can also make management of non-physics entities really simple.

The only reference to this class is inside the BulletBehaviour’s Collided callback function, when the bullet is deleted from the scene. Just before it’s deleted, the bullet called MarkerBehaviour.Create, passing itself in as parent.

As covered in the previous post, this allows the new entity to automatically pick up the parent entity’s position and orientation, and we just need to remember to set its parent back to Null to ‘free’ it from the relationship.

In this case, that means a marker appears at the bullet’s final location and the Behaviour/component system handles the rest.

Note that there’s no other update or management code: the marker appears in the scene, then on each call to Scene.Update, its OnUpdate method is called.

Here, OnUpdate simply deletes the marker if it’s existed for more than one second. That’s it!

The rest of the code is the sprite creation, similar to the way bullets were set up — creating a global template sprite and simply copying it, the new copy picking up the parent bullet’s position and orientation, which will be where it collided with the ground. (The orientation is ignored, as sprites default to ‘billboard’ mode, remaining permanently upright. (You can modify this via Sprite.Mode and the SpriteMode enum options.)

Here’s the marker code in full:


Const MARKER_HEIGHT:Float = 10.0

Class MarkerBehaviour Extends Behaviour

	Global MarkerSprite:Sprite
	
	Field time_created:Int
	
	Function Create (parent:Entity)
	
		If Not MarkerSprite
			
			MarkerSprite			= New Sprite ()
			MarkerSprite.Visible	= False
			MarkerSprite.Scale		= New Vec3f (2.0, MARKER_HEIGHT, 1.0)
			
		Endif
		
		New MarkerBehaviour (MarkerSprite.Copy (parent))
	
	End

	Method New (sprite:Sprite)
	
		Super.New (Cast <Entity> (sprite))
		
		AddInstance ()
		
		sprite.Parent	= Null
		sprite.Visible	= True
		
		sprite.Move (0, MARKER_HEIGHT * 0.5, 0)
		
		time_created	= Millisecs ()
		
	End
	
	Method OnUpdate (elapsed:Float) Override
	
		If Millisecs () - time_created > 1000
			Entity.Destroy ()
		Endif
		
	End
	
End

One minor quirk: I was experimenting with passing in a Sprite instead of a plain Entity for the New method, hence there is a cast to Entity for the Super.New call. This wasn’t really necessary, but as with previous classes at least shows you can do things in different ways. Just pick what suits you and be more consistent than this!

Now you can place thousands of entities into your game scene and leave them to their own devices — no other management code or lists of entities needed!

Just remember to call Scene.Update in your OnRender method. (See island.monkey2, the main code file.)

Note on ‘missing’ markers in demo

You may notice that markers sometimes don’t appear, particularly on steep hills or sides of buildings.

My best guess is that they are simply buried inside the geometry, the collisions being detected part-way through the steep hillsides, etc, and the steeper the hillside, the less chance the marker will protrude through the ground. Setting the ground alpha to partly transparent shows all markers appearing, so I believe they’re simply inside. (A possible alternative explanation is that the island model geometry is a little messed-up; this can even be seen in normal demo use, with floating walls and cut-off slopes here and there, and the triangles do look a little odd, and possibly even flipped in places, when ground alpha is set to < 1.0.) I suppose it would be possible to manually calculate the correct vertical position using the mesh geometry and adjust the markers accordingly, but of course it's not overly-important for this demo!

Monkeying Around with mojo3d: more Behaviours… with bullets!

Sunday, January 6th, 2019

The last post was mainly about rearranging the code, wrapping up models and rigid bodies into the Behaviour classes they belonged in.

This post is a little more fun, adding bullets and simple ground markers that delete themselves after a second.

The bullets are remarkably hard to capture in a screenshot, for reasons too boring to go into, but they look way better in-game!

WebGL Demo

I’ve also added a WebGL demo here so you can try online:

Island WebGL Demo

As before, use Cursors to move, A & Z to speed up/slow down, plus Space to fire. Additionally, the plane now has yaw control, which is controlled via Q and E.

Plane changes

There have been a few changes to the plane’s physics, most obviously in the addition of yaw controls, but also in that the plane will now pitch and yaw when banking. This means that banking causes the plane to turn as a real plane does (the pitch pulls the banked plane around) and also starts losing height, via yaw.

It’s far from a proper simulation, but still feels believable enough for the most part, at least in terms of a simple arcade-style game.

Interestingly, adding the pitch and yaw during banking made it much easier to target and hit the buildings, as it behaves much more like a real plane now, so movement is more predictable. (It’s still pretty difficult, mind!)

It’s hard to believe the underlying physics representation is still just a simple sphere!

Source code — what you’ll need

As usual, the intention of these posts is that you scroll through the code at the same time, in order to see what each section is doing.

Download the code and media below before continuing. Open up island.monkey2 in the default Monkey2 editor, Ted2Go, and additionally, bullet.monkey2 and marker.monkey2. (The easiest way is to simply drag and drop all three files into the Ted2Go window.)

IslandDemo source and media [Note that this is NOT a secure server, but the zip file contains only source code — text — and the 3D media. Run it through your virus scanner for peace of mind!]

Double-click the island.monkey2 tab to make it the default build file and hit F5, or the Run icon, to try it out.

Switch to the bullet.monkey2 tab, where you’ll find the following extract:


Const BULLET_LENGTH:Float	= 15.0
Const REMOVE_DISTANCE:Float	= 750.0

Class BulletBehaviour Extends Behaviour

	Global BulletModel:Model
	Global LastBullet:Entity
	
	Field start_pos:Vec3f
	
	Function CreateBullet (parent:Entity)
	
		If Not LastBullet

			BulletModel			= Model.CreateCylinder (0.33, BULLET_LENGTH, Axis.Z, 8, New PbrMaterial (Color.White))
			BulletModel.Visible	= False

			New BulletBehaviour (BulletModel.Copy (parent))

		Else
			If LastBullet.Position.Distance (parent.Position) > BULLET_LENGTH * 2.5
				New BulletBehaviour (BulletModel.Copy (parent))
			Endif
		Endif
		
	End
	
	...

We have two constants, BULLET_LENGTH and REMOVE_DISTANCE, with some default values defined.

The ‘bullets’ in this example are really just stretched cylinders, intended to look similar to tracer streams, and their collision bodies are the same for simplicity.

  • BULLET_LENGTH sets the ‘length’ of each bullet;
  • REMOVE_DISTANCE allows us to remove bullets from the scene after travelling a given distance.

This means our bullets are in fact 15m (50ft) long — a fine example of the fraudulent hand-waving peculiar to creating games!

The bullets will travel for 750m before being removed from the scene, so as to limit the number of active physics bodies and related 3D entities.

The start_pos field holds the bullet’s starting position in a Vec3f, which is a 3D ‘vector’ of floating-point type — a structure that holds the x, y, z elements of a three-dimensional position in a single value. (The f in Vec3f refers to float).

Don’t be afraid of Vec3f if this is new to you! We will be assigning start_pos with the bullet model’s position later on, and it’s as simple as:

start_pos = Entity.Position

We can therefore easily store the entity’s 3D position in a single variable.

The behaviour class definition follows, including two class global variables holding Model references:

  • BulletModel: a base model we can just copy for every bullet;
  • LastBullet: a reference to the last bullet fired. This allows us to avoid firing new bullets until the last bullet has travelled a given distance, a simple way of controlling the fire rate.

LastBullet was originally of Model type, but I changed this to Entity just to avoid casting from Entity later on, in the OnStart method. It’s not important, just shows different options; you can decide for yourself how you prefer to handle this in your own projects — just be more consistent than I have here!

I’ve chosen in this case to create a globally-accessible CreateBullet function from which we’ll create new bullets in the main source file. In island.monkey2, you’ll find this function called within OnRender. It passes in the PlaneBehaviour’s Entity reference, for reasons we’ll see shortly:

If Keyboard.KeyDown (Key.Space) Then BulletBehaviour.CreateBullet (plane.Entity)

The main reasons for doing it this way, rather than calling New BulletBehaviour directly, are:

  1. It shows that we can wrap the bullet model into the BulletBehaviour class, as an alternative to the way the plane model was set up, where we loaded the model in the main OnCreateWindow function and passed that in to New PlaneBehaviour;
  2. but more importantly, it allows us to check the distance between the last bullet fired and the ‘new’ bullet, prior to creating it, and to keep all of this checking bundled within the BulletBehaviour class. (We don’t want to create a new bullet if the last bullet hasn’t travelled far enough.) This avoids the need for checking to be implemented from the call site — the location from which a function is called — and also does away with the need to hold a reference to the last bullet fired inside the main code.

Instead, CreateBullet will only call New BulletBehaviour after performing these basic checks.

CreateBullet receives a parent entity, which will be the plane model, then checks if this is the first call to CreateBullet, in which case LastBullet will not yet exist; if LastBullet doesn’t exist, it creates the base model, BulletModel, and spawns the first bullet.

The New BulletBehaviour call sets up LastBullet, so that on the next call (and all subsequent calls), the Else block will be called instead, carrying out a distance check prior to creating a new bullet.

(In fact, it would probably more sensible to rearrange things so that the less-common case falls within the Else block, ie. creation of the bullet! However, it’s not speed-critical, so I’ll just leave as-is — I think it’s a little clearer as to what is happening this way.)

Once created, the base BulletModel will be copied and modified for each new bullet fired.

BulletModel is a simple cylinder model, with 0.3m (1ft) radius to enhance visibility (more cheating!), and the 15m length defined earlier, aligned along the z-axis (so orients ‘into’ the screen, rather than vertically or across). It has 8 segments to keep it simple and a basic white material.

As this is just a base model to be copied for each actual bullet, it’s hidden from display so as not to leave it floating in the scene.

In the usual case, where BulletModel and LastBullet have already been created, we check the last bullet’s position relative to the plane:


	If LastBullet.Position.Distance (parent.Position) > BULLET_LENGTH * 2.5
		New BulletBehaviour (BulletModel.Copy (parent))
	Endif
		

Notice again that we have a handy reference to each entity’s Position property; Position is a Vec3f, which in turn has a handy Distance method available.

To see this, click on the word Position and press F1 twice: this will open up the Position property documentation. Click on std.geom.Vec3f, then on Vec3 (the base 3D vector class). This will list all of the data and methods available to Vec3f. You’ll find Distance listed further down.

Here, we are using LastBullet’s Position Vec3f to call the Distance method, and we simply pass in the plane’s Position for comparison, receiving a single distance value as a result.

From trial-and-error, I’ve chosen to spawn a new bullet only if the last bullet is over 2.5 times the bullet length away from the plane. If not, nothing happens and the function is done — no bullet is created.

This initialisation could be simplified greatly by having a specific externally-called function that sets up BulletModel (which would have to be manually called in the main code file prior to using New BulletBehaviour), but I preferred having everything all wrapped up here — and a single test for LastBullet’s existence really isn’t going to be having any practical effect on processing speed.

To clarify the New BulletBehaviour call here:

New BulletBehaviour (BulletModel.Copy (parent))

Here we pass in a copy of the base BulletModel — the Model class has a handy Copy function to create a standalone copy of a model.

Note that Entity.Copy cannot copy entities with attached components, such as physics bodies, hence BulletModel is nothing more than a basic model with no rigid body or collider.

The parent reference was passed in as CreateBullet’s only parameter, set as the plane model when calling from the main source file.

One really handy aspect of creating an entity with a specified ‘parent’ entity is that it picks up the parent’s position and orientation upon creation — so our bullet is already aligned correctly with the plane.

You could instead pass in the plane’s position and orientation, and use these to align the bullet, but I find the parent solution much more convenient.

The only downside to this method is that you need to remember to remove the parent relationship once in position, so as not to affect the bullet’s position or rotation when you modify the plane. We’ll be doing this inside BulletBehaviour’s OnStart method.

Using OnStart

I’ve updated both the plane and bullet classes to move the physics body setup into the OnStart method, instead of doing this during New.

The reason for this was that bullets were causing the program to crash when spawned: it turns out OnStart can be called before New has completed!

Although the rigid body was set up during New, OnStart had already been called by Scene.Update before this happened.

As OnStart makes reference to the body, which didn’t yet exist, the program would crash. Carrying out the physics setup in OnStart avoids this, since we’re making sure the body exists before we reference it.

I don’t fully understand why this works the way it does, but just bear in mind that Scene.Update may call OnStart before New has completed! Just follow this arrangement in your Behaviours to avoid the same fate: leave the New method as a simple Super.New and AddInstance.

Here’s the beginning of OnStart:


	Method OnStart () Override
	
		Entity.Visible					= True
		Entity.Move (0, -2, 15)

		Local bullet_velocity:Vec3f		= Entity.Parent.RigidBody.LinearVelocity + (Entity.Basis * New Vec3f (0, 0, 300))
		
		Entity.Parent					= Null
		
		Local collider:CylinderCollider	= Entity.AddComponent <CylinderCollider> ()
		
			collider.Radius				= 1.0
			collider.Axis				= Axis.Z
		
		...

Entity here is a copy of BulletModel, which was hidden upon creation, so we first make it visible.

The bullet will be sitting at the plane’s position by default, with the same orientation, because the plane model was specified as its parent upon creation in CreateBullet. Any movement will currently be relative to the plane’s position and orientation, so we just move it down 2 metres and ahead 15 meters, as judged by simple trial and error.

Next, we are storing the linear velocity of the parent entity’s rigid body (the plane’s body), so that the bullet carries the same speed, to which we are adding a further forward vector, which is modified by the bullet’s Basis (orientation):


	Local bullet_velocity:Vec3f		= Entity.Parent.RigidBody.LinearVelocity + (Entity.Basis * New Vec3f (0, 0, 300))

'

After setting an independent entity’s position and orientation via a parent, remove the parent!

We then, importantly, remove the parent/child relationship between bullet and plane, by setting the entity’s parent to Null.

Note that we stored the parent entity’s speed before removing this relationship — Entity.Parent is no longer available.

We’ll apply bullet_velocity via ApplyImpulse shortly…

Next comes the collider and rigid body setup, as usual, but in this case we have an additional feature:


		Local collider:CylinderCollider	= Entity.AddComponent <CylinderCollider> ()
		
			collider.Radius				= 1.0
			collider.Axis				= Axis.Z
		
		Local body:RigidBody			= Entity.AddComponent <RigidBody> ()
			
			body.Collided				=	Lambda (other_body:RigidBody)
												
												MarkerBehaviour.Create (Entity)
												
												Entity.Destroy ()
												
											End

			...

Notice that body.Collided weirdness!

Rigid Body Collisions

This is how the Bullet Physics SDK gives us collision responses — by way of a callback function.

In this case, the function is a ‘lambda’ function, which is defined ‘inline’ without a name, rather than separately (as with standard functions), and, importantly, lambda functions are able to access variables within the current scope: that’s why we can access ‘Entity’ here, inside the function.

Don’t worry about the details, just define it like so and fill in what you want to happen when this body collides with another:


Lambda (other_body:RigidBody)
												
	' Response actions go here!

End

This code when be called upon collision, every time the body is touching another. Note that the other_body parameter is filled in by the physics system, allowing you to retrieve that body’s information.

The function will be called continuously while in contact, eg. while a ball is rolling along the ground, not just at the point of collision.

In our case, we create the ground marker (which I’ll cover in a separate post) and destroy the bullet:


	MarkerBehaviour.Create (Entity)
	
	Entity.Destroy ()

When the bullet entity is destroyed — removed from the 3D scene — so are all of its components, which in this case means automatic destruction of both collider and rigid body. We don’t need to do anything more than destroy the entity.

The other_body parameter gives us a reference to the other body involved in the collision. For multiple colliding bodies, this function will be called against each one in turn. By default, we collide with all other rigid bodies, and their responses are handled automatically.

(I’ll probably go into collisions more in a later post, including the grouping of different types of bodies, and filtering these for different responses in the Collided lambda function.)

You can, by the way, add further collision callback functions if you want. Try uncommenting these lines in the code:

'			body.Collided				+=	Lambda (other_body:RigidBody)
'												Print "Hi"
'											End

For each collision, this extra function will additionally print “Hi” to the console. Note the += syntax here, which adds to the ‘list’ of functions to be called.

Nearing the end, we set the start position (as noted earlier), set LastBullet to the bullet we’ve just created, and set the entity’s colour randomly to one of four built-in colours:


		start_pos						= Entity.Position
		
		LastBullet						= Entity
		
		Select Int (Rnd (4))
		
			Case 0
				Entity.Color			= Color.White
			Case 1
				Entity.Color			= Color.Yellow
			Case 2
				Entity.Color			= Color.Orange
			Case 3
				Entity.Color			= Color.Red
			
		End
		

Finally, there’s a tricky little bit of casting required in order to set the ’emissive factor’ in the bullet’s material, which here gives the bullets a sort of glowing effect:


		Local model:Model				= Cast <Model> (Entity)
		Local pbrm:PbrMaterial			= Cast <PbrMaterial> (model.Material)

			pbrm.EmissiveFactor			= Entity.Color

		Entity.RigidBody.ApplyImpulse (bullet_velocity)

I broke this down into a couple of steps for easier reading:

  1. Cast the behaviour’s Entity reference to a Model: basic entities don’t have PbrMaterials, which provide more advanced rendering functionality than the plain Material an entity has. Models can use PbrMaterials, and we need this type of material to use EmissiveFactor;
  2. The material needs to be cast to a PbrMaterial in order to access EmissiveFactor, and for simplicity we are assigning a PbrMaterial handle here;
  3. Now we can set the EmissiveFactor: this takes a Color, and we’re just using the entity’s existing colour (which we just set), causing the material to ‘glow’ in this colour, preventing shadows from appearing as they naturally would, and thereby giving a nice glowing effect.

OnUpdate

Lastly, we have OnUpdate, applied on each physics update (60 frames per second by default, independent of the actual FPS):


	Method OnUpdate (elapsed:Float) Override
		
		Entity.RigidBody.ApplyForce (New Vec3f (0.0, -40.0, 0.0))
		
		If Entity.Position.Distance (start_pos) > REMOVE_DISTANCE
			Entity.Destroy ()
		Endif
		
	End

The first line is a cheat! The bullets weren’t falling as much as I wanted them to, so I manually applied a force to push them down more than gravity is doing by default.

We then simply test how far the bullet has travelled from its start position; if it’s travelled more than REMOVE_DISTANCE (750 metres, set at the top of the file), the bullet is destroyed. Simple!

In summary

There’s a lot here to pick up, but just take it a little at a time and compare constantly with the actual source code.

I’ll address the final aspect of the demo, the ground markers, in a follow-up shortly. They’re extremely simple in comparison, but show an easy way to use Behaviours to manage non-physics objects too.

Monkeying Around with mojo3d: wrapping physics behaviours

Sunday, December 16th, 2018

This post continues on from Monkeying Around with mojo3d: physics behaviours.

As always, the intention of this post is that you scroll through the code at the same time, in order to see what each section is doing.

Note that this time, I have moved the PlaneBehaviour class into its own file, to more accurately reflect how a real-world project would be organised.

Download the updated code and media below before continuing:

IslandDemo source and media [4.6 MB; note that this is NOT a secure server, but the zip file contains only source code — text — and the 3D media. Run it through your virus scanner for peace of mind!]

Open up both island.monkey2 and planebehaviour.monkey2 in the Ted2Go editor, and double-click the island.monkey2 tab to set it as build file; a litte + sign will appear in the tab to make this clear. Making island.monkey2 the build file means that even if you’re tweaking the PlaneBehaviour class, you can just hit Ted2Go’s Run command (F5 or the rocket icon) to build island.monkey2.

You can double-click the tab again to de-select island.monkey2 as the build file. When no file is set as the build file, whichever tab you hit Run from will be treated as the build file.

Splitting into separate files makes the main file much simpler, and makes jumping between the PlaneBehaviour definition and the main code a simple switch between tabs, rather than scrolling up and down between class and main code.

Importing Code

Note that the main code file now features this line near the top to import the PlaneBehaviour file, making the PlaneBehaviour class accessible to island.monkey2:

#Import "planebehaviour"

You can specify the full name, like so, if you prefer:

#Import "planebehaviour.monkey2"

 

Before we proceed, a ‘Mea Culpa’…

In the last post, I ended by saying:

In the real world, you probably wouldn’t want to have the collider and rigid body setup carried out in the main body of the code, but instead do this within the OnStart method of the Behaviour so as to encapsulate all of the plane’s data.

As the New method of Behaviour only allows the passing-in of an entity parameter, this can make things a little tricky, so I’ll address my solution to this in the next post.

While the first line is true, the second line is… well, an embarrassing mistake!

I had thought that the Behaviour class’s New method could only take the default entity:Entity parameter listed in the Monkey2 documentation.

However, PlaneBehaviour extends Behaviour, and we can in fact define our own overridden New methods!

What this means, in short, is that we can easily pass in any parameters we want to PlaneBehaviour, and therefore set everything up inside the PlaneBehaviour class, instead of partly in the main program and partly inside PlaneBehaviour (without the trickery I had intended to demonstrate!).

The Old

Previously, the plane was set up outside the PlaneBehaviour class, in the main program (within OnCreateWindow), like so:


		Local plane_size:Float					= 16.83 * 0.5
		Local plane_box:Boxf					= New Boxf (-plane_size, -plane_size, -plane_size, plane_size, plane_size, plane_size)
		
		Local plane_model:Model					= Model.Load ("asset::1397 Jet_gltf_3B3Pa6BHXn1_fKZwaiJPXpf\1397 Jet.gltf")

			plane_model.Mesh.FitVertices (plane_box)
			plane_model.Mesh.Rotate (0, 180, 0)
			
			plane_model.Move (0.0, 5.0, 0.0)

		' Cull hidden tris...
		
		For Local mat:Material = Eachin plane_model.Materials
			mat.CullMode = CullMode.Back	
		Next

		' Physics setup...
		
		Local plane_collider:SphereCollider		= plane_model.AddComponent <SphereCollider> ()

			plane_collider.Radius				= plane_size * 0.6
		
		Local plane_body:RigidBody				= plane_model.AddComponent <RigidBody> ()

			plane_body.Mass						= 10954.0
			plane_body.Restitution				= 0.5
			plane_body.AngularDamping			= 0.9
			plane_body.LinearDamping			= 0.1
			plane_body.Friction					= 0.0

		plane									= New PlaneBehaviour (plane_model)

This is not ideal, as it places all of the technical setup in the main body of the code, reducing the simplicity of setting up another plane, or several planes, as you have to define a collider and rigid body every time. When this complexity is all wrapped-up into the class, setting up a new plane can be greatly simplified, requiring nothing more than a simple call to New PlaneBehaviour.

The New

In this revised version, the setup code simply loads the model and sets up some basic values for physics processing:


		Local plane_model:Model					= Model.Load ("asset::1397 Jet_gltf_3B3Pa6BHXn1_fKZwaiJPXpf\1397 Jet.gltf")

		' Core values for physics...

		Local mass:Float						= 10954.0
		Local roll_rate:Float					= 550000.0
		Local pitch_rate:Float					= 250000.0
	
		' And pass plane_model into PlaneBehaviour, where physics
		' will be applied...
		
		plane = New PlaneBehaviour (plane_model, mass, roll_rate, pitch_rate)
		

The model is loaded and then a few core values are set up — mass, roll rate and pitch rate (technically single elements of the torques that will be applied to specific axes).

Finally, New PlaneBehaviour is called, passing in:

  • plane_model
    the model loaded and set up earlier;
  • mass
    the mass, defined above as 10954 kg;
  • roll_rate
    the roll rate (element of torque to be applied to the z-axis);
  • pitch_rate
    the pitch rate (element of torque to be applied to the x-axis).

These values are arbitrary — just the values I chose to pass in — but you could easily amend this to suit yourself.

For example, if you decided to simply hard-code the mass, roll rate and pitch rate as fixed values inside the class, you could remove these elements (from both the call here, and the PlaneBehaviour New definition) and simply set them inside PlaneBehaviour’s New method.

The idea here is simply to demonstrate the ability to pass in changeable values to New PlaneBehaviour.

In a professional setup, other programmers might be calling your New PlaneBehaviour method to set up enemy aircraft, for example.

If you’ve hard-coded these values inside PlaneBehaviour, anyone (including you!) trying to tweak these for different types of enemy plane would have to edit the PlaneBehaviour class, affecting all other planes in the game! By allowing these values to be passed in per-plane, they can be defined by the calling programmer without affecting any other aircraft behaviours.

Down inside PlaneBehaviour, we’ve gone from this:


	Method New (entity:Entity)
		
		Super.New (entity)
		AddInstance ()

	End
	

… to something that looks much more complex, but is in fact much the same code as before, just moved from outside the class to inside the class:


	Method New (entity:Entity, mass:Float, roll_rate:Float, pitch_rate:Float)
		
		Super.New (entity)
		
		AddInstance ()

		Local plane_size:Float					= 16.83 * 0.5
		Local plane_box:Boxf					= New Boxf (-plane_size, -plane_size, -plane_size, plane_size, plane_size, plane_size)
	
		' Get a Model-specific handle to the entity:
		
		Local plane_model:Model					= Cast <Model> (entity)
		
		plane_model.Mesh.FitVertices (plane_box)
		plane_model.Mesh.Rotate (0, 180, 0)
			
		plane_model.Move (0.0, 5.0, 0.0)

		' Cull hidden tris...
		
		For Local mat:Material = Eachin plane_model.Materials
			mat.CullMode = CullMode.Back	
		Next

		' Physics setup...

		Local plane_collider:SphereCollider		= entity.AddComponent <SphereCollider> ()

			plane_collider.Radius				= plane_size * 0.6
		
		Local plane_body:RigidBody				= entity.AddComponent <RigidBody> ()

			plane_body.Mass						= mass
			plane_body.Restitution				= 0.5
			plane_body.AngularDamping			= 0.9
			plane_body.LinearDamping			= 0.75
			plane_body.Friction					= 0.0

		roll_torque								= roll_rate
		pitch_torque							= pitch_rate
		
	End
	

We’re now loading and adjusting the model here in PlaneBehaviour.New and doing setup of the physics collider and rigid body where they really belong. (The code remains much the same as it was before, when it was defined in OnCreateWindow, but is now properly encapsulated within the class.)

The first two lines remain as before, creating a Behaviour from the entity (plane model), and placing it into the scene; just treat these as necessary boilerplate lines, as mentioned last time — copy and paste!

We’ve then moved all the loading and positioning code into the class itself, setting up the plane’s size, bounding box and adjusting the mesh to fit, then positioning the plane at its start point.

One line that will almost certainly need explanation is this, just after the size and bounding box definition:

Local plane_model:Model					= Cast <Model> (entity)

Behaviour requires that an Entity object be passed in, Entity being the ‘lowest common denominator’ class of 3D object.

All 3D objects in mojo3d are variations of the Entity class: Model, Light and Camera are all extended versions of class Entity (each of these extends the Entity class), but each has its own domain-specific functionalities, some of which would include:

  • Model: Holds a mesh and materials to be applied to the mesh;
  • Light: Holds a direction, range and colour;
  • Camera: Holds near and far ranges, field of view, ability to render to a Canvas, etc.

Entity, on the other hand, gives us the core positioning and rotation methods used by Model, Light and Camera, as well as many other basic functionality.

Because Behaviour.New only gives us a reference to an entity (not a Model, or a Camera, for example), we need to ‘cast’ the entity to the specific class of entity we expect to operate upon; in this case, a Model.

We create a local variable to hold this Model reference:

Local plane_model:Model ...

… and call Cast (entity) with the modifier to receive the type of entity required:

... Cast <Model> (entity)

The plane_model variable therefore now holds a reference to the entity upon which we can call Model-specific methods.

After setting up the model, we cull any backfacing triangles, as before, and then set up the collider and rigid body — again, as before.

Lastly, the renamed roll_torque and pitch_torque fields (which are still technically misnamed!) are set up from the roll_rate and pitch_rate parameters passed in.

In Summary

  • Use the extended Behaviour’s New method to get the entity (usually a model*) and any required data into the class, and set up your model and its physics collider and rigid body. (There is certainly a case to be made for leaving the model adjustment outside of the class, but this will be down to your own judgement.)* Note that there’s no reason you can’t pass in other types of entity, such as a camera you’d like to be physically controlled.
  • Use OnStart to do any initial startup processing; in this case, we get a handy typing shortcut to the physics body and set the plane’s initial impulse force.
  • Use OnUpdate to process any custom updates, such as applying player input forces to the entity, as happens here.

Other Tweaks

  • The rigid body’s LinearDamping value has been tweaked to 0.75; previously, in a tight turn, the plane’s rotation appeared unrealistically tight. This looks a little better.
  • The plane’s collider visualisation (the semi-transparent sphere you could enable) has been removed.
  • Support functions have been to aerialcamera, which is the only place they’re used.

This post has probably been rather technical, but just look at the code itself and cross-reference here for anything you don’t quite ‘get’!

In the next post, I’ll demonstrate the power of Behaviours a little more clearly by adding bullets, created as Behaviours, placed in the world and then left to their own devices, with no additional management code necessary!

Sucking hard: The Wedding Present, 7 Nov 2012

Thursday, November 8th, 2012

Saw The Wedding Present last night, doing their [Steve Albini-engineered] Seamonsters album in its entirety, and thankfully padding it out either side, whereas they used to play only an album and then piss off:

I must have been standing right behind whoever filmed this, so it’s a pretty good memento!

They were really good (as always), and pretty loud too, but Gedge’s guitar parts should have been way louder for my taste. He’s still great, though: funny, unassuming and still a brilliant songwriter — see recent album Valentina.

Their Japanese support band, Toquiwa (tok-ee-wah), were very entertaining too, in a different kind of way:

Their singer’s mangled Engrish (she knew what she was doing), keyboard stomping, impressive beer-downing skills and infectious, boundless enthusiasm won over all; unfortunately, the video above doesn’t show any of that, being from another gig…

 

Everyone is Wrong

Thursday, November 8th, 2012

Many years ago, I posted my interpretation of the lyrics to Lyle Workman’s Everyone is Wrong (as performed by Frank Black and the Catholics in a 1996 John Peel session) on frankblack.net, but Google no longer finds the post, and doesn’t recognise the lyrics. Here they are in the hope that Google can find them again:

I saw a man in shackles/Shut down ’cause he heeds cynic drone/Opinions everywhere/Foolin’ around inside his head/Shake them off/And sic the dog/Believe me/Everyone is wrong/They called his genius shallow/They called him every name to show they had word-skill/Judgment from everyone/From the sublime, the deft and the numb/Sticks and stones/May break my bones/Believe me/Everyone is wrong/If you must evaluate/You must appreciate it/I don’t give weight to your proudly jaded rape of my creation/Everyone is wrong.

A righteous ‘fuck the critics’ song! Here it is, for reference (right-click to save):

Everyone is Wrong