Blog
Page: 0 2 3 4 5 6 7 8 9 10 ... 15 ... 20 ... 25 ... 30 ... 35 ... 40 ... 45 ... 50 ... 55 ... 60 ... 65 ... 70 ... 75 ... 80 ... 85 ... 90 ... 95 ... 100
Scribe: Installer script hooks
Date: 14/7/2016
Tags: scribe scripting
So you know those red bars that appear in Scribe when it wants to install something? I've just added the spell check dictionaries to that so you have to confirm there install. This allows you to make sure you have a working internet connection before download a dictionary. But I thought it would be cool to add some scripting hooks for the install bar and the actual install itself. So take an example script like this:
function BeforeInstall(App, Msg, Actions)
{
    Actions.Add("Scare");
    Msg = Msg + " (BeforeInstall was here)";
    return true;
}

function Install(App, Action)
{
    if (Action == "Scare")
    {
        MsgBox(App, "Boo!");
        return false;
    }
    
    return true;
}

function Main(App)
{
    if (!AddCallback("OnBeforeInstallBar", "BeforeInstall"))
        MsgBox(App, "Couldn't add BeforeInstall");
    if (!AddCallback("OnInstallComponent", "Install"))
        MsgBox(App, "Couldn't add Install");

    return 1;
}
What it does is install 2 callbacks, one for the missing capability bar, and one for the install itself. It messes with the message and buttons available to the install bar. Then adds a new "action" that is caught later in the "Install" function to put up a dialog box. Might be useful for managed installs of Scribe.
(1) Comment | Add Comment

The week of Mac bugs
Date: 7/7/2016
Tags: mac carbon
This week has been mostly about making the Mac build of Scribe more polished. It's always lagged behind the Windows build. And now it's catching up fast:

1) HIViewSetFrame inside kEventControlDraw is bad

For many years I couldn't work out why some calls to HIViewSetFrame wouldn't work inside some application I was writing. It turns out that called that inside the kEventControlDraw callback is actually bad. It leaves lots of the controls half painted of showing the previous contents of the screen. And no amount of calling HIViewSetNeedsDisplay is going fix it. The compositor thinks the old position of the control is up to date and won't repaint it.

Ultimately if you find you need to move a control during the re-paint you have to send a message to yourself and do it after that particular repaint has finished.

2) Apple Event handling

After 4 years I finally found the reason why Lgi apps wouldn't respond to AppleEvents that were passed to them on startup. I answered my own stack overflow question today.

3) Editing the Application Menu

The Scribe Application menu, that sits between the Apple menu and File menu has never had the normal "About" and "Preferences" items. And while there is a lot of discussion on how to do that for Cocoa apps, there is little to no information for Carbon apps. And yes, Scribe is still a Carbon app, although it does use a bunch of modern APIs for text and so on. I tried mixing some Cocoa calls to get at the right menu, but that didn't work. Then after hours of searching the internet I finally stumbled on to a mailing list post that describes how to do it. So it seems it's possible, just really obscure.
(0) Comments | Add Comment

Drawing windows BUTTONs on coloured backgrounds
Date: 4/7/2016
Tags: windows
The default windows BUTTON drawing behaviour draws a 1px grey border around buttons. If you place the button on a parent window that is a different colour you get an ugly border like this:



So I decided to see what I could do about that. It turns out that there is no "setting" that can fix that. You either draw the whole control yourself or let the system draw it. Now I want the system look without the wrong coloured border. So I reimplemented the WM_PAINT like so:
case WM_PAINT:
{
    if (!GetCss())
        break;

    // This is the effective background of the parent window:
    GCss::ColorDef bk = GetCss()->NoPaintColor();

    // If it's not the default...
    if (!bk.IsValid())
        break;

    // Then create a screen device context for painting
    GScreenDC dc(this);
    
    // Get the control to draw itself into a bitmap
    GRect c = GetPos();
    
    // Create a HBITMAP in the same size as the control 
    // and the same bit depth as the screen
    GMemDC m(c.X(), c.Y(), GdcD->GetColourSpace());
    // Create a HDC for the bitmap
    HDC hdc = m.StartDC();					
    // Ask the control to draw itself into the memory bitmap
    SendMessage(_View, WM_PRINT, (WPARAM)hdc, PRF_ERASEBKGND|PRF_CLIENT);
    // End the HDC
    m.EndDC();

    // Draw correct background
    m.Colour(bk.Rgb32, 32);
    // The outside 1px border (unfilled rect)
    m.Box(0, 0, c.X()-1, c.Y()-1);
    // The 4 pixels at the corners
    m.Set(1, 1);
    m.Set(c.X()-2, 1);
    m.Set(1, c.Y()-2);
    m.Set(c.X()-2, c.Y()-2);

    // Now stick it on the screen
    dc.Blt(0, 0, &m);

    // Skip over calling the parent class' callback procedure.
    return true;
    break;
}
What it does is get the system to draw the button into a memory bitmap and then "fix" the border, before blting the whole thing to the screen. Now it's implemented with LGI types and classes, but the whole idea is fairly straight forward that you could implement in raw Win32 API calls. This fixes the border and still looks native:



The key is re-purposing the WM_PRINT message to get a copy of the control's native look. For the moment I've limited this to just when running on Windows 7, because I think Windows 8 and 10 use flat colour controls and [possibly] don't need fixing like this.
(0) Comments | Add Comment

Logic Pro X bounce time
Date: 27/4/2016
Tags: logic audio
I was doing some mixing today and the bounce time in Logic Pro X seemed very long. Much slower than I was expecting. (Bouncing is basically "rendering" all the audio down to a stereo track for those wondering).

I opened up the Activity Monitor and Logic was reading 10mb/s off a disk capable of 100mb/s. CPU was about 30%, i.e. it's using one core (of my 4 core i5 machine). In true programmer fashion I started to google the problem and it appears that people are having trouble with various plugins being slow. I didn't have anything much loaded, just lots of audio tracks. But I tried disabling the reverb to see if it made any difference. None whatsoever.

I began wondering about the disk speed. Maybe it's causing problems? So I copied the project (all 50GiB) onto a fast USB3 flash drive and run my test again. The export of 2 songs went from 2 minutes to 20 seconds. Uh, ok, wow that's pretty different.

Then I started to wonder about why that is so. The USB3 flash drive is capable of 190MiB / second, and the original hard drive can do 110MiB / second. It's in the same ball park really... so why the order of magnitude performance difference? I think it comes down to the read strategy of Logic. Now I'm just guessing here, but I think it reads small blocks (KiB) of audio from the files to keep the in memory buffer of audio small. This means in large projects with many audio tracks seeking from one file to the next constantly trying to get the next little bit of the audio. This is kinda worst case for a mechanical drive that has to move the head to a new location between each file. Seeking is expensive. On the USB key, seeking is almost free... so it runs fast.

Now the authors of Logic could have bumped the buffer size up considerably so that when trying to access lots of audio tracks there would be more reading and less seeking between files. In my case with 16GiB of RAM to burn that would be fine, but might be an issue with smaller RAM sizes. You certainly can't afford any paging during audio work. Still Logic should be able to see how much RAM is available and size it's internal buffers accordingly.

Obviously for anything to do with "live" audio the buffer size has to be tiny, so that the latency is short. But for pre-recorded material buffering up a few MiB's of audio shouldn't be an issue.
(0) Comments | Add Comment

MC2 April Progress
Date: 3/4/2016
Tags: mc2
So here is a scary idea... I'm playing next weekend in my live band. Should I use the MC2 for the first time? If I get a bunch of stuff finished I don't see why not, although I'll definitely have the MC1 packed in case it doesn't go smoothly. The main hurdle will be the expression pedal ports which I haven't really done any work towards other than getting the ADS1115 chip to show up on the I2C bus. Nothing like a dead line to get you moving.

Running progress:
  • 1/4
    Wired up the rest of the encoders, and their buttons. Implemented the software side to read all their state changes. I now have 6 encoders fully working.
  • 2/4
    Fixed the button handling to only do something of the "down" event. Lowered the maximum brightness of the Neopixels a lot... otherwise they are almost white instead of the selected colour. This also uses less power, which is nice.
  • 3/4
    Implemented software button debouncing to remove duplicate up/down events. Also added "held" buttons events that fire if I button is held down for more than 1200ms. This is useful for hiding advanced features. I might use it to access the Y settings of Axefx2 blocks connected to Instant Access buttons for instance.
  • 4/4
    Implemented tuner support on the higher resolution screen of the MC2. Yay for not having to make custom text characters to display a line.
    Hooked up the encoder output to the Axefx2's EXTERN 1-8 CC messages. Limiting the range to 0 - 127 and adding a little acceleration if the user is turn the dial a lot. I've managed to get one twist of the dial to go from 0 to 127 and yet retain some fine control when moving slowly. It seems to be reasonably good transitioning from non-accelerated to accelerated.
    Bought some stereo switched insulated jacks for implementing 2 expression pedal ports. The system supports 4 but I only need one at the moment. Also bought some plastic knobs for the encoders, just till I work out what ones I really want. Ideally I'd get something that is suitable for recessed shafts. Most knobs cater to raised shafts, where the nut is above the panel surface.
  • 5/4
    Drilled and deburred holes to mount the MIDI and expression pedal jacks on the case.
    Soldered together the expression port jack and hooked it up to the ADS1115 chip. The stereo socket is a DPDT switch as well which allows me to detect when there is no expression pedal plugged in. Basically I set +3.3V for that condition, and start about +3V for maximum expression.

    Wrote the corresponding code to read the value from the ADS1115 chip over the I2C bus. This was pretty straight forward. I keep a min and max value to auto-calibrate to the pedal.
    And that technically means the MC2 is out of Alpha into Beta! All the basic functionality works. However there is a lot of road testing to go :D
  • 6/4
    Added a row of labels under the IA config buttons to say what the buttons are currently configured as.
    Added an continuous parameter mimic control to display graphically the position of things like encoders/expression pedals. This looks like a circle, with a line showing the "amount" radially, just like the Axefx2 parameter display:

    Fixed some display bugs when switching presets.
    Added a script to start the MC2 application on startup. Obviously I want the program to start automatically when I'm using the system live.
    Added a button on the setup page to shutdown Linux. There is a confirmation dialog before that happens. Now I can start and shutdown the whole thing without a keyboard attached. Excellent!
    Took the plastic off the touchscreen... oooooooooooh! ;)
  • 7/4
    Added a MIDI disconnect event to the Raspberry Pi hardware layer. Basically if it doesn't see any MIDI for 3 seconds it flicks over to "disconnected" mode. Normally the tempo messages keep this from happening. There is no easy way at a hardware level to see if MIDI cable has been unplugged.
    Going to start "testing" things by doing my personal rehearsal during the day. Then tonight I have the full band rehearsal.
    Fixed the select scene 'n' IA button selecting scene 'n+1'.
    Removed the nice highlights on the buttons to improve rendering speed. Currently the GUI thread is running the controller code, and message passing is limited by the redrawing of the screen. This is not ideal and I will fix it at some point but I just want it to work ok for the weekend. So things like the expression pedal send a message from the hardware IO thread. And it's laggy because of the screen updates. At some point I'll need to break out the profiler and find out where the time is going. Most likely there are a number of CPU bottlenecks in the graphics and text handling code.
    Changed the expression pedal reads to happen every 8ms instead of 16. Again in an attempt to improve latency. I can probably improve that again by reading up on all the ADS1115 modes. I think it can do like 800 samples a second but I'm getting a lot less than that ATM.
  • Band Rehearsal
    There were no major issues at the rehearsal. It all worked pretty much as I wanted it to. The only minor issue is that if I configure a bunch of IA buttons the text on the labels is pushing the layout off the right edge of the screen:

    So I'll have to fix that in the layout code. One problem is that the edge of the touch screen doesn't really work, so if things are too near the edge you can't activate them. The second issue is that is just looks bad. Hahah.
    I'm really liking the layout of the hardware buttons. Having the IA buttons along the near edge is much better for triggering things during the song. And the tap tempo on the corner is also better than the location on the MC1. Being able to dive in and setup a new IA button quickly was also really useful (I decided I needed some Phase90 in my life last night).
    I also noticed a text clipping bug when text is off the right edge of the screen it wraps around to the left edge. Hmmm should fix that sometime.
  • 8/4
    Fixed the layout bug by adding some CSS to the text label cells:
    max-width: 59px;
    The text overflows a bit for larger labels, but at least the position of the buttons doesn't move.
  • 10/4
    Live play testing!
    Yes I took it out to play live this weekend. It went pretty well overall. For the most part everything worked as well as I had hoped. The main glitch was at the very end of the first set the buttons stopped responding for a little while. Touch screen was still good so I just shut it down and restarted for the next set. It didn't affect my performance though. After rebooted it seemed to settle in ok and the 2nd set went without any problems. The expression pedal lag was still there obviously but I worked around that. There may be some display issues with the IA LEDs. I thought I noticed some block IAs in the wrong state after scene changes. But I was pretty busy just getting on with playing rather than analyzing the IA states. Something to follow up later.
(0) Comments | Add Comment

MC2 March Progress
Date: 1/4/2016
Tags: mc2
After when seems like forever I bring you an update on the MC2 project. The good news is that most of the hardware is now working, including MIDI Input/Output, the Neopixel chain, the I2C bus to the GPIO expander chips, which in turn connects to the buttons and encoders. In short I can now use it to change presets on the Axefx which is like the bare minimum functionality.

Some of the issues I've had to sort out:
  • Very slow compile times on the Raspberry Pi
    I'm only using a Pi B (version 1, rev 2) so it's got a single core running at 700MHz which frankly is molasses slow. So I decided that it was worth getting a cross compiler working on something with more grunt. It took days of mucking around, and 3 different builds, copying off almost the entire Pi's worth of headers and libraries, but it now works. More importantly it's fast. My main dev box (3.8ghz i5 /w 16GiB of ram) chews through the code very quickly, and then copies the binaries down to the Pi over the network.
  • PiTFT touch screen not working correctly
    The behaviour I was seeing was the cursor stuck in the top left, and the x & y axis' were swapped. I ended up building SDL from source and then inserting a pile of logging during the mouse driver setup only to discover that it was using the default mouse driver instead of the touch screen driver that I had configured in the environment. It turns out that as I'm running the code as root (sudo) the environment is different than my normal user account. Ok, so now I just set the right env vars in my C code before initializing SDL. Which forces it to do the right thing on any account.
  • I2C bus not working / unreliable
    This came down to adding 1000uF electrolytic over the 3.3v supply line, and also adding 0.15uF decoupling caps over the +V/GND pins of the GPIO expander chips. Also I had to change the pull up resistors connected to the SDA+SCL data lines from 4.7k to 10k.
  • Neopixel chain stopped working
    Eventually I found a cold solder joint on the ground pin output. Only after disassembling it completely, including the button harness and taking the plastic backing plane out.
  • MIDI input not working / garbled
    This has actually taken most of the week to sort out. The hardware for the input side seemed ok, and I even did see some incoming MIDI at one point. Initially it was garbled and I tweaked the baud rate with system settings. It seemed to work for a while then stopped again. I got very frustrated with not being able to see the logic signals in the circuit so I went and bought a Bus Pirate which can read both the UART and do logic analysis. I tested all the hardware I could in isolation. I went over the traces like 6 times. I tried the optical isolater chip in my MC1 and everything appeared to be good. I even pulled the diode out and tested it in isolation. I tested the Rx+Tx pins of the Pi by hooking it up to the Bus Pirate and had the Pi talking to the PC. Then I tried minicom and saw the incoming Tempo messages from the Axefx! Ah, so the hardware IS good, and thus I started looking at the software side again. It turns out that in more recently Linux kernels you can see custom baud rates in code. Most of the people getting MIDI working on the Pi are doing system config settings. But it's a hack. Using an API to set the speed to the exact right value is way better. Now the existing code snippets kinda get you there, but for me I had to merge the old code and new code to get something that works for me. This is the final result:
            int MidiHnd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
            if (MidiHnd > 0)
            {
                struct termios2 tio;
                ioctl(MidiHnd, TCGETS2, &tio);
                
                tio.c_cflag = BOTHER | CS8 | CLOCAL | CREAD;
                tio.c_iflag = IGNPAR;
                tio.c_oflag = 0;
                tio.c_lflag = 0;
                tio.c_ispeed = 31250;
                tio.c_ospeed = 31250;
    
                ioctl(MidiHnd, TCSETS2, &tio);
            }
    
    The MIDI output was an easy fix: just turn the 4011 logic chip the right way around. And boom: working! Hahaha... in my defense it has a little stamped circle at the other end of the chip. Which is sometimes used to mark the "1" pin. Grrrr.
Oh and here is some video showing it working:
(0) Comments | Add Comment