Cmake stupidity...
So given this snippit:
add_dependencies(my_target jansson)
I get this error:
The dependency target "jansson" of target "my_target" does not exist.
Ok so I did 'add_directory' that, so what if I did this:
add_dependencies(my_target jansson)
Now I get:
add_library cannot create imported target "jansson" because another target with the same name already exists.
Really? It just errored out because it didn't exist? You can't have it both ways Cmake!!!

Cmake: you get what you paid for!

Tags: cmake | (1) Comment | Add Comment

UDP and Ubuntu 14/Windows incompatibility
For the last few weeks I've been mucking around in the background with an application I've called "ClipShare" that basically sits on the network and allows you to copy and paste between different machines. It supports text, images and files at the moment. I'm sure such a thing already exists but I like how it auto-detects all the machines running it on the network via UDP broadcast and supports Windows, Mac and Linux. It's far from production ready, it still crashes a bit and hangs up during file transfers sometimes. But over time I'm sure I'll iron that out.

Things like Samba, VNC and VM's (Vmware/Virtualbox) tend to have support for things like clipboard and file sharing. But in my experience they break very easily and it's 50/50 if they'll work or not. Hence having an alternative for getting the data across.

In testing I had a Ubuntu 14 VM running on a Windows host and for the life of me couldn't get the UDP packets to go from Ubuntu to Windows. I could see the packets arriving in Windows land via Wireshark but the recvfrom wouldn't get the packet. The packet wasn't large, just 40 bytes or so. In researching the issue I found that IP packets have a checksum, so I figured out how to get Wireshark to test the checksum. It confirmed the checksum was good. I could see using 'netstat -s' that there was an increasing count of 'Received Packets Discarded'. So Windows for reasons unknown was discarding the UDP traffic from Ubuntu. I tried turning off the Windows Firewall. No difference.

So then I decided to spin up my Ubuntu 16 VM and test the exact same code there. And sure enough it's working fine. So in conclusion I believe that at the OS level, Ubuntu 14 has some busted networking code. I can't tell what's wrong. Maybe it's a Windows thing. But it's basically meant I'm moving to Ubuntu 16 for all my Linux dev stuff. The main reason I had a Ubuntu 14 environment was that I had a working Raspberry Pi cross compiler install and I hate messing with a working env just for the sake of upgrading. However that broke recently anyway so it seems that the last reason for keeping 14 just disappeared.

Fun times.

Tags: linux ubuntu networking | (1) Comment | Add Comment

Apple and the curse of VNC
For many years now it's annoyed me greatly that trying to connect a Windows VNC client to a MacOSX VNC server has resulted in terrible horrible slow and glitchy performance. Mac to Mac is fine, Windows to Windows is fine, but cross platform? Nope. In fact the Mac to Mac performance is better than any of the Windows or Linux implementations. The reason being that Apple has added a range of proprietary extensions to make that use case better than normal VNC. This is also why the Windows -> Mac case is sub-optimal. It seems that the fast VNC modes that everyone else talks aren't spoken by the Apple VNC server implementation. So what to do? Well the solution that I'm employing at the moment is to... not use the Apple VNC server implementation! Turn off screen sharing in the options and install VNC connect. The cross platform performance is quite decent, running the server and client from the same vendor. Maybe 90% as fast as the all Apple case?

Embrace, extend, extinguish am I right?

You either die a hero or you live long enough to see yourself become the villain.

(I will try and find a free solution in the medium term, and will update this post if/when I do)

Tags: mac vnc | (0) Comments | Add Comment

sem_post funkiness on Linux
I moved the Linux implementation of the GThreadEvent class (.h, .cpp) over to the sem_open, sem_post, sem_wait calls a little while back.

Initially I used named semaphores and that seemed to work ok. But after a few weeks I noticed that sometimes the call to sem_post would just quietly NOT increment the semaphore count, while still returning 0 (Success). Which causes the listening thread blocking in sem_wait to never wake up. Crucially this would break the destructor / exit loop of GEventTargetThread.

Googling this didn't turn up anything useful. I believe I was using the API correctly and the documentation is very sparse. Anyway I implemented the semaphores using the sem_init/sem_destroy (anonymous) and it seems to be robust. Still, I'd like to know what the deal is with the named ones. The general pattern of behaviour I would see is:
Fun times. I checked it under valgrind and no weird memory accesses. Sometimes it would work ok and exit gracefully. But most of the time it would hang.

Tags: linux | (0) Comments | Add Comment

Visual Studio 2013 crash...
This is just awesome:

The trace is something like this:
>	clr.dll!DontCallDirectlyForceStackOverflow(void)	Unknown
 	clr.dll!CLRVectoredExceptionHandler(struct _EXCEPTION_POINTERS *)	Unknown
 	clr.dll!CLRVectoredExceptionHandlerShim(struct _EXCEPTION_POINTERS *)	Unknown
 	ntdll.dll!RtlpCallVectoredHandlers()	Unknown
 	ntdll.dll!RtlDispatchException()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	clr.dll!DontCallDirectlyForceStackOverflow(void)	Unknown
 	clr.dll!CLRVectoredExceptionHandler(struct _EXCEPTION_POINTERS *)	Unknown
 	clr.dll!CLRVectoredExceptionHandlerShim(struct _EXCEPTION_POINTERS *)	Unknown
 	ntdll.dll!RtlpCallVectoredHandlers()	Unknown
 	ntdll.dll!RtlDispatchException()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	clr.dll!DontCallDirectlyForceStackOverflow(void)	Unknown
 	clr.dll!CLRVectoredExceptionHandler(struct _EXCEPTION_POINTERS *)	Unknown
 	clr.dll!CLRVectoredExceptionHandlerShim(struct _EXCEPTION_POINTERS *)	Unknown
 	ntdll.dll!RtlpCallVectoredHandlers()	Unknown
 	ntdll.dll!RtlDispatchException()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	ntdll.dll!ExecuteHandler@20()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	ntdll.dll!ExecuteHandler@20()	Unknown
 	....repeated a lot....
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	ntdll.dll!ExecuteHandler@20()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	ntdll.dll!ExecuteHandler@20()	Unknown
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown
 	KernelBase.dll!_RaiseException@16()	Unknown
 	[External Code]	
 	cpfe.dll!scout_parser::class_def_or_decl(struct a_source_point const &,struct a_type_specification &)	Unknown
 	cpfe.dll!scout_parser::tag_type_def_or_decl(struct a_source_point const &,struct a_type_specification &)	Unknown
 	cpfe.dll!scout_parser::type_specifier(struct a_type_specification &)	Unknown
 	cpfe.dll!scout_parser::type_specifiers(struct a_type_specification &)	Unknown
 	cpfe.dll!scout_parser::simple_declaration(struct a_type_specification &,class antlr::TokenRefCount)	Unknown
 	cpfe.dll!scout_parser::property_or_event_or_simple_declaration(struct a_type_specification &,class antlr::TokenRefCount)	Unknown
 	cpfe.dll!scout_parser::general_declaration(struct a_type_specification &,class antlr::TokenRefCount)	Unknown
 	cpfe.dll!scout_parser::general_declaration_with_error_recovery(struct a_type_specification &,class antlr::TokenRefCount)	Unknown
 	cpfe.dll!scout_parser::declaration(struct a_type_specification &,class antlr::TokenRefCount)	Unknown
 	cpfe.dll!scout_parser::declarations(void)	Unknown
 	cpfe.dll!scout_parser::translation_unit(void)	Unknown
 	cpfe.dll!_run_scout_parser()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	cpfe.dll!_compute_il_prefix_size()	Unknown
 	cpfe.dll!_edg_main()	Unknown
 	cpfe.dll!_corresp_init()	Unknown
 	cpfe.dll!tag_parse(int,unsigned short const * *,unsigned short const *,bool,struct IEdgeSnapshotSession *,class a_scout_parser_interface *)	Unknown
 	vcpkg.dll!CExtStore::TagParseHelper(struct HBase,unsigned short const *,struct IEdgeSnapshotSession *,unsigned short const * * const,int,enum FileType)	Unknown
 	vcpkg.dll!CExtStore::TagParseCpp(struct HBase,unsigned short const *,struct IEdgeSnapshotSession *,unsigned short const * * const,int)	Unknown
 	vcpkg.dll!CCppParser::Parse(struct HBase,unsigned short const *,struct IEdgeSnapshotSession *,unsigned short const * * const,int,class CSharedPtr >)	Unknown
 	vcpkg.dll!CPopulateWorkItem::Work(void)	Unknown
 	vcpkg.dll!CWorkItem::InvokeWork(unsigned int)	Unknown
 	vcpkg.dll!CWorkQueue::Work(bool,unsigned int,unsigned int)	Unknown
 	vcpkg.dll!CWorkerThread::Work(void)	Unknown
 	vcpkg.dll!CWorkerThread::Work(void *)	Unknown
 	kernel32.dll!@BaseThreadInitThunk@12()	Unknown
 	ntdll.dll!__RtlUserThreadStart()	Unknown
 	ntdll.dll!__RtlUserThreadStart@8()	Unknown

I want to see if any one else is getting this...

Tags: vs2013 | (1) Comment | Add Comment

Ho ho ho
The merry little elves at Memecode have been working away at all hours of the night to bring you a working Rich Text (HTML) editor in Scribe to put in your Christmas stockings.

With the release of Scribe v2.1.33 there is enough functionality to write email with styles. The reply/forwarding side of things isn't as good as the composition of new email. For a variety of reasons. And the control is still definitely in "Alpha" (i.e. incomplete functionality, still contains bugs, possibly show stopping ones).

It would be a excellent idea to reset the reply/forward formats to their default values, because I've updated the default template for HTML reply/forward. If you have a custom template for plain text, save that before you reset the templates in File -> Options -> General -> Reply / Fwd templates -> Reset.

Also go into your signature settings and configure a HTML sig for each account with an identity.

I'll set some expectations first... with the pros: And some cons:
To switch between plain text and HTML quickly use Edit -> Use HTML Editor.

Do not use the HTML control for production emails. If it matters, use the plain text compose control. Otherwise I'd like to hear how it goes.

Tags: scribe html-editor | (0) Comments | Add Comment

Rich Text / HTML support in Scribe
There has been a lot of people asking about the Rich Text / HTML editing support in Scribe and so while not fixing crash bugs I'm actively developing a new control to support styled text editing.

So that those that are interested can track the progress I'm publishing my internal spreadsheet of bugs and features:

Broadly speaking my hope is to have a very basic control working by the end of the year. Good enough that you can write and reply to email with, even if there isn't a lot of support for styling. Maybe some basic stuff like bold, colours and font size.

Tags: scribe | (2) Comments | Add Comment

Refactoring for performance
A few weeks into actually using the MC2 I realized that the response time of the expression pedal was quite poor, running in the 100-200ms range. After doing some tests I worked out that it was because of the way messages were passed from the hardware thread that received the events, like analog to digital reads for the expression pedal, to the user interface thread, where they would be processed and sent back out the hardware thread to the Axefx. The problem with this was the the Raspberry PI is quite slow (or at least the version I'm using) and the user interface update speed was lagging. If the user interface is being updated, it's not processing messages. Hence the delay. But fixing it wasn't straight forward, because all the user interface code and Axefx code were all jumbled up like this:

So I took all the code that relates to the Axefx, and all the code that updates the user interface and separated them out into their own source code files. I called the Axefx specific code the "logic". Now I had 3 separate bits of code: Now I originally had 2 threads. And I decided that unless I really had to I would stay with those 2 threads, but the logic had to move from the UI thread, into the hardware thread. This meant that responding to MIDI and hardware events was decoupled from the user interface updating. Like this:

So hardware events, like the expression pedal value changing, would by processed immediately in the same thread and an outgoing MIDI message could be sent almost immediately, even if the UI was busy doing something. The latency was hugely improved. It's got to the point that it no longer has an impact musically. It seems to respond instantly.

In doing this I realized that I could hide all the details of each block of code behind a message passing interface. Which is excellent for thread safety. There was a little shared data that I wrapped in a mutex. But all in all the design feels nice and clean.

In fact I loved the design so much I'm rewriting i.Ftp to use the same architecture. Oh yeah, and because it was kinda badly written and wouldn't port to modern UI systems that don't have thread safe UI APIs.

Tags: mc2 | (0) Comments | Add Comment

Negative ADS1115 readings
I've been using an ADS1115 to convert the analog voltage from the expression pedal input, which is just a potentiometer really, to a 16 bit value. On the weekend I had a gig and both at the rehearsal and the set the expression pedal would flip to 127 (the maximum) when in the minimum position. It was also behaving erratically, the full range of output values was compressed into a very short throw of physical movement. I didn't technically need it for the gig so I just unplugged it.

So today I thought I'd get to the bottom of it. After switching on the logging and reproducing the issue it was apparent that a lot of "plugged" / "unplugged" events were happening. This was due to the values coming from the ADS1115 were bouncing between very low values (say 0 - 100) to very high values (65530 - 65535). I started by putting the multi-meter in voltage mode over the input pin of the ADS1115 and ground and found that the lowest voltage was about 0.1V which is, well, correct for the minimum position. So that led me to believe it was solely a software issue. Looking at the code that does the read, I found it was assuming the 16bit value was a unsigned integer. But that fact that the value was jumping to 65500 made me wonder if maybe the ADS1115 was giving me a signed value instead. So I changed the code to assume signed behaviour and now the values all seemed to follow each other as the pedal moves back and forth. Then checking with the data sheet:
The ADS1113/4/5 provide 16 bits of data in binary twos complement format
Ugh, ok so I should read that more carefully. Still it going slightly negative like that even with a positive voltage is a bit weird to me. Oh well, I'm just going with max(0, AdcReadValue) for the moment and it seems to be working just fine now.

Tags: mc2 | (0) Comments | Add Comment

Scribe: Installer script hooks
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)
    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.

Tags: scribe scripting | (0) Comments | Add Comment

The week of Mac bugs
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.

Tags: mac carbon | (0) Comments | Add Comment

Drawing windows BUTTONs on coloured backgrounds
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())

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

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

    // 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
    // End the HDC

    // 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;
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.

Tags: windows | (0) Comments | Add Comment