posted
These are the release notes for the 1.08 release of synSpace: Drone Runners, a space game for Android that supports player-created starMaps, shipShells, pilotFaces, synthPatches, sequencerGrooves, and alien Ham Radio via the vocoder.
Available in the Google Play Store for phones and tablets, and on Amazon for Kindle Fire HD devices
Summary:
* fixes crash on newer devices when asking for microphone permission.
* Obeys the 'new' API23 permission setup. Asks for fewer permissions overall
* reduces the android minimum SDK from 22 to 18. I only raised it before due to a misunderstanding with google
* adds support for using a USB MIDI controller as an input device
* removed the dependency on Google Play services for access to Google Drive. Now uses a more standard API for general file access (local or cloud, based on your providers) which works for both Google and Amazon Fire devices
* made a zillion more changes to the vocoder, always a moving target
* fixed any UI nuisances that were nagging at me :-)
posted
OK! Just released 1.07 for Google Play store, now to update Amazon... if I can remember how to do that. New coding will go to version 1.08, documented here as it happens!
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
And Amazon is now updated. Less than 24 hours, on xmas eve. Pretty Good, Amazon!
And that apparently includes automated testing on a variety of kindle devices. They then send me a summary and noted that I failed on the newest 8" Kindle (2018 version). I have a zillion of these, probably, so I know it works on them in general. But I have found in the past that after an OS update, that which once worked can sometimes stop working.
Also, when developing, you tend to use the same devices over and over, and that's not a fair test against a device which is being installed for the very first time. It's easy to create a dependency on a file that a real user would not have yet.
They don't send me a stack, however, so I have to actually duplicate the error at home. (Google Play Store sends me full stackdumps on my rare crashes... super rare)
Or maybe it's another permission system change. There have been a lot of those lately and I be;oeve API 23 is the boudnary at which I have to use an entirely different system. But will Kindle and GPS both require that at thhe same time? We'll see!
I do hope they find a balance between "not checking enough" and "scaring the crap out of you"
Anyway, I hate to think someone got a new FireHd8 for xmas JUST to play synSpace :-)
---
Oh, but my POINT was this gave me an excuse to buy another FireHD. And the 8" was my favorite back when it was $90, and now its more like $40
posted
And, after confusing myself further, I think I am now API23 compliant, formally asking for the scary permissions (microphone) just before I need them, and being more graceful in the case where permission is denied (less crashing!)
But now the min api is 21, where before it was 19 (I think), and I'm not sure I want to do that. I know I am forgetting something that changed, that is probably why I changed in the first place.
AND, because I use Google Play Services to access your Google Drive (to import a star map file that you're working on), I have to ask for the GET_ACCOUNTs permission, which to me is super scary and I don't want that responsibility so I am upset that GPS demands I do so.
But in 1.07 I added the ability to import from a local file (that you dragged into the device over USB cable or something), and didn't notice that it isn't limited to just local storage. It can import a file from pretty much any cloud storage your device knows about. Which includes Google Drive, so I no longer need my old code (and maybe no longer need that permission! and maybe can unlink from GPS, which scares me and slows down startup)
So that's the GOOD news, but the bad news is that apparently that technology only works for importing files and not for sending new files to storage. I still use the GPS stuff to send to google drive.
But I could change that to send only to local storage (and then demand you USB that into your main desktop as needed). It's not functionality needed by anyone but the map developer and it's probably very convenient for them. So I might do that if it gives me a chance to unlink from GPS and that permission.
I also ask for CAMERA permission, but only so you can use your camera to create your FACE bitmap, and for that I don't talk to the camera API directly, I just send an intent that launches your camera app (and then IT should check for permission). So I don't think I need to ask for that one, and it's probbaly confusing that I do. but I'm trying to follow the rules.
It's been confirmed that the newest 2018 Kindle Fire HD 8" is api23 and barfs when 1.07 uses the microphone without the explicit runtime check. And that also happens on a modern LG thinq phone, so probably it fails on all the newest devices at the moment (presumably all fixed in this next release 1.08)
I could deploy that immediately, but first I have to worry about api19. I guess I should build it for 19, then try to submit it to GPS, and give them the chance to say '19 is too old!' Unless I had some compelling reason to leave 19...
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
ah, too bad, I missed the chance to mention 1.08 on Jan 8. And 2019 could be thought of as referring to API19 and API 20. Numerologically significant day, shame I missed it.
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
And I still have not released 1.08 with the fix. If YOU have a newer device where synSpace appears to crash on launch, you could probably get past that by manually granting it the permission 'record_audio'
But that would feel weird. The issue is that Android made some changes to how they handle permissions, and isolated several as being 'dangerous' and requiring additional scrutiny. So instead of the user just approving it once at time of app install, the app must dynamically ask for permission BEFORE EACH USE of the feature in question, using a 'new' API (only new to people like me who don't keep up)
Anyway, a completely reasonable change, and it took me a couple tries to adapt to it, hence the lack of a 1.08 release so far. I think what I have now is correct but I still have to test it against my pile of tablets.
Ironically, I am REMOVING my permission check for CAMERA, since I think the way I do that does not require permission. (user taps my button and I send an intent to their camera app which starts up and waits for user to snap photo and confirm they want to use it -- no secret photo possible). I think I only need permission to use the low-level camera APIs, which would be cool, but not this game.
Anyway, 1.08 within a week, I promise. I think. I can't help but want to polish a couple more things, though.
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
While I haven't posted a 1.07 release notes video yet (have stuff to edit), here is a 'lecture' movie where I go on and on about the vocoder and harmonics again.
Ostensibly these are the 1.08 release notes, but we'll see.
posted
I think I improved the note start/stop detection. I have to use an unusual 'clock' signal, and it turns out it wasn't incrementing during periods of silence.
I really should refactor the vocoder to be executed inside the high priority audio thread, then I would have a perfect clock.
Also, I changed my state machine a while back to look for 'retriggering' (when a note gets loud again before going completely silent), and now that that's working, I can have a much longer debounce period for the end of the note, which reduces stuttering (a long note encoding as several shorter ones)
Encoded songs still sound pretty 'plodding' as opposed to 'airy' but the number of extra notes (bogus notes) has come way down.
But I still miss really short notes, and notes that happen to also be at harmonic frequencies. But I had a vocoding of Gotye's Hearts a Mess where I could actually make it out, which was a first.
Still, this is a pretty good snapshot, so I should backburner additional vocoder work for 1.09 and focus on just polishing 1.08 and testing with all versions of android.
As I test things, I have to repeatedly go through various UI paths, and over time you tend to notice small bugs that you don't want to interrupt your flow to fix (and sometimes that's a good call... since small bugs often require large fixes)
But my problem is that I accumulate a handful of these because I don't write them down, and then don't think of them until the next time I experience them. That's bad. always make a note. Make it easy to make notes. some text file you keep open, or any file you have at hand if it's an emergency.
For example, 1.08 fixes the bug that if you started synSpace from scratch and immediately tried to use the vocoder, it would not appear until after you opened/playedANoteOn the piano. I 'ignored' that one probably a hundred times (and it only took a few minutes to fix it)
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
Yay, I think I have ended the tyranny of Google Play Services, though I imagine I am still linked to it somewhere, I no longer need to require scary permissions on its behalf.
I now use the CREATE_DOCUMENT intent and that does everything I need with no permissions required at all. So I adapted all my import/export commands to use the new tech.
So now you can save and load files from the cloud (or local flash drive) on both Kindle and Nexus devices. And you get a nice chooser for the cloud provider of your dreams.
It's a little quirky if you do it several times rapidly. UI hangs until all the cloud stuff is done.
I also got THIS CLOSE to actually doing tractor beams.
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
Well, last night I only wanted to work on inappropriate things, so I tried to pick the least inappropriate of my opportunities and went with "supporting external MIDI controllers over USB"
I've traditionally thought there was lag in the touch interface, and that if I supported 'real' controllers, I could remove that. Since then, I have come to feel most of the lag is in the audio out pipeline (I send a buffer to the OS, and it just sits on it until it has more data, then plays with lag)
So, assuming I get this to work, it might well not resolve the actual issue (hard to play faster than 20 BPM with the lag)
So I am prepared for disappointment.
As to how it's done, it's not too bad. I think I finished the actual USB support part of it already (detects the USB device is plugged in and gets permission to use it, then connects and starts receiving data (no data seen yet)
It's a little inconvenient since the tablet only has one USB port, so I can't debug and play at the same time... I wonder if a USB hub would work there.
Also, I have only tested with one device (an AKAI midi controller - small), but none of the identification values shout out "I am a MIDI controller!" so I don't know how I am supposed to work that out other than maintaining a big list of vender and product IDs. Which maybe there is a list of on line or something, but that's a hassle to keep up to date. There is a 'class' value which clearly could be used, but no value for 'midi'
Of course, if I were willing to force people to upgrade to newer devices, the latest android has full MIDIonUSB baked in. More reason why it is silly to do this at all, let alone at this moment in time.
But it's what my heart wanted to work on, and I did a good job. I always do a good job in the beginning, then turn it into spaghetti by the end :-)
Thin end of the wedge though, how can this not turn into wider MIDI support?
---
Which brings me to the Yamaha REFACE DX. How did I manage to not hear about this? (actually, I am sort of glad I didn't, since apparently it started at $600 and is now under $300)
I always wanted a DX7 (not anymore -- too big, heavy, and dusty), but lacked the funds (or the compelling NEED).
So this remake DX, at a reasonable price, is extremely appealing to me (though apparently I am told I have to wait for my birthday before getting it)
Plus it works as a MIDI controller, so I can use THAT excuse (I need it for testing, honey? It's partly tax deductible?)
Anyway, something I am excited about.
MARKETING MESSAGE FOR YAMAHA
So, in case you were off planet like me, they made FOUR similar, small (37 minikey), synthesizers, each capturing some iconic bit of Yamaha history, but with modern stuff ('virtual analog' i.e. 'digital').
The DX is the FM synth version (4 operators and a bunch of effects), but they also have a CS which is a neat twist on basic modular (subtractive), the CP which is specialized to do 'pianos' (samples, I think), and the YC (? I always think 'young christian' when I see that. It's basically a bunch of sampled 'organs' and sounds very church-ey (or ice-rink-y) and it's the only one that doesn't appeal to me at all.
I could see getting a DX and a CS, but lack the mad piano skills to justify a CP.
BUT, then you have to factor in "but you can already make all those sounds, for free, with SynSpace:Drone Runners, the amazing android game... well, almost free).
So I think probably just the DX, for nostalgia reasons.
And if my new MidiOnUSB allows me to record DX Patch settings for posterity, why WOULDN"T I add that as well? They have an app for that, but it sounds like it only works on iOS, so maybe synSpace:Drone Runners could be the defacto android interface for it :-)
Unless Yamaha wouldn't like that, and I want Yamaha to like me (send me free stuff, Yamaha!)
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
OK, picked up on this and got the data traffic to work and wrote a quick and dirty midi parser (just enough to get note on/off messages) and now I can play my synth with an external midi controller, wewt!
I need to make it an option, and move some of it to its own thread, and solve Yet Another stuck note situation, but looks good.
I own 2 cheap midi controllers and both work, but:
* they don't work 'the same' ! * the blockTransfer call returns completely different stuff between them * every message has a bogus starting byte * on one of the controllers, it pads the entire buffer with nulls. The other just sends the expected midi stream.
But my parser seems to survive both and other than the stuck notes, it works well.
HOWEVER, i think this confirms that, as expected, the lag is actually in the audio stream. I have the same lag whether I use the midi controllers or the touch interface.
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
Did some googling and found the actual spec for "MIDI on USB".
The deal is that while USB is a 'serial' protocol (like midi), it apparently is 'chunked' in 32bit values (4 bytes. So, a typical MIDI message like
90 44 40
that only needs 3 bytes, is 'padded' to four and sent as an atomic unit 'on the USB stream'
Come to think of it, this is probably because MIDI uses the 'standard AUDIO USB driver' and that is probably thinking in terms of sending stereo 16 bit audio streams at 44.1KHz. I'm glad I typed that, feels clarifying and relieving.
Honestly, the 'bulkTransfer.read()' function is extremely unusual in its behaviour, and possibly under-documented, and possibly 'at the mercy of' the standard drivers. At face value, it's like a file read where you provide a buffer to receive some data, and a count of how much data you'd like/can handle, and a timeout in the case where that much data is not available.
The return value is the amount of data it actually returned. Later Android releases added a non-blocking version of the call.
ANYWAY, it turns out that:
* it is very fussy about how many bytes you must ask for, and asking for an incorrect amount results in no data at all.
* it often provided more than you asked for
* the return value is often less than helpful (like if you ask for 64 (because that is the only legal amount to ask for), and it only has 62 before the timeout occurs, it will return with those 62 values placed in your buffer, but will return -1 as the return code, so you have no idea as to '62'. You just know what you got was less than what you asked for.
And that sounds like a BUG, unless you add "but this behaviour varies with the USB device 'class' and for the AUDIO class, it apparently is optimized to send 64 bytes of data per frame, and when that is used for MIDI instead, they just pad out the rest of the frame as needed. No MIDI message is longer than 64 bytes (other than SYSEX, I believe), so it's actually much nicer than 'normal' midi, since you don't really need a state machine to decode it, since you get all the arguments at the same time (for a given message).
And in the case of my mystery extra lead-in byte.. that turns out to be official MIDI-ON-USB 'spec', and is a 'cable' number, so that a single USB stream can carry multiple 'virtual midi cables' (looks like up to 16 cables... each cable then has 16 midi channels, and each midi channel can send events.
The events are sent WITHOUT TIMESTAMPS which makes sense for a live performance. I hit the key, the message squirts out the wire and travels at USB speeds to the synth, and it starts playing the note the moment it decodes the message. If the wire is slow, then it feels laggy to the musician.
The sequencer, if any, catches the events and provides a timestamp relative to the moment you pushed the record button. Then, when the time comes to play back the recording, the sequencer is the only one that looks at the timestamps, and just waits until the time has rolled around, and then emits the event back out (to the synth, who doesn't know the difference between live or recording)
SO THERE ARE NO TIMESTAMPS IN THE MIDI STREAM.
I type that in caps mainly as a challenge to reality to prove me wrong. I know there is a way to embed timing in the MIDI stream because I used to do that back in synJam. The MIDI file is just a bunch of midi messages, but there is some message that means 'wait N beats before processing the next message'
And yes, the time stamps are part of the MIDI FILE spec. in the FILE spec, not the midi STREAM spec, which can always thought of as being a live performance stream (that is often fed by a canned event recording)
NO TIMESTAMPS IN THE MIDI STREAM
Anyway, thanks for the therapy session!
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
Midi IN feature appears to be complete, except for dropped packets. If I hit two keys at the same time, there is a high probability it won't receive both events.
My USB foo is still weak, though. My mental model is of a bunch of devices joined on a wire, where one of them is the 'host' and everyone listens to what the host says.
The host then says "endpoint 21, I want you to send your data to endpoint 57" at which point everyone else shuts up, and endpoint 21 gets to broadcast for awhile. In theory to everyone, but maybe only one guy cares.
At some point the host gives control to a different pair of endpoints, and eventually, everyone gets to send their data to their peers as needed.
In this context, my app(on tablet) is the host, and there is only the one slave device (MIDI controller) though it offers three interfaces, which I'm not sure I fully understand. Each has a class/type, and I only operate with 'USB AUDIO' device interfaces.
And the wire only runs one way, so my USB hardware is receiving a stream from the MIDI controller with no pushback at all to the MIDI controller. The speed is set by I dunno what. I think USB does some sort of arbitrage, maybe with some priority event, but I imagine AUDIO gets pretty high priority, and I would be surprised if the MIDI controller was to blame. I imagine it is feeding the USB just as it should, and I am somehow dropping the incoming when it is too soon after another packet.
but logging just shows the blockRead request got no data. Well, that reminds me, I need to experiment with the timeout value and see if that has an affect....
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged
posted
After I chat with my smart friend, I changed to the queue()/qaitRequest() api and that worked instantly with no more dropped messages. I think that's a better match to what is going on in USB and the bulkTransfer call is trying to make it look like a stream when really it's a series of packets.
Anyway, seems to now have flawless midi controller support (though I assume my midi state machine probably has some bugs, all I need it key messages and they appear to be fine)
next goal: release 1.08
-------------------- He knows when you are sleeping. Posts: 10652 | From: California | Registered: Dec 1998
| IP: Logged