Thursday, December 15, 2022

Let me show you my ARSE.

Arbitrarily Routing Sound Engine

 I, and I'm sure a lot of other people, have a need that's seriously not being met by current systems on the market. I am referring to Windows-based systems here, as I'm sure you could probably do something like this with JACK on Linux, but ain't nobody got time for that.

What I need is a system that will allow me to map any number of audio inputs to any number of audio outputs simultaneously on Windows. So, for example:

  • Microphone, Discord audio, Game audio, Music and Overlay Audio routed to one input of OBS
  • Microphone, Discord, Game and Overlay Audio (but no Music) routed to a second input of OBS, for VOD capture
  • Microphone routed to Discord for chat (possibly game audio routed there too, so participants can "watch" without double audio confusedness/weirdness on their part)
  • Microphone, Discord, Game and Music all being captured simultaneously, in separate tracks, for later combining manually as part of an edited clip or highlight reel for YouTube
  • And, of course, Discord, Game, Music and Overlay all being played through headphones for the user to hear

This would also work well for Podcasters, being able to capture multiple microphones, and/or call-in guests, along with Soundboard audio in a multi-track session, without having to worry about sync or external sources, for later mixing and combining as necessary. You could also have plugins like an auto-ducking plugin, so when someone talks, another source (or sources) have their volume cut, like DJs on the Radio.

Existing Solutions

Currently it seems the best option is the Virtual Mixer software Voicemeeter (and it's increasingly more complex variations, Banana and Potato). While they can work, they're very limiting - There's no multi-channel recording, and they rely on having several virtual devices that you manually send audio to or consume audio from. While they do have recording built-in for Banana and Potato, it mixes the inputs down to a single output, which is not ideal. Software like this seems to be based on the same paradigm as hardware mixers - Mixing inputs down onto a (number of) output buses. While this works for some needs, it's not as flexible as it could be, and with a little work I think this could be a lot better.

Presentation (User)

So what does the user see? This is where it could get difficult. One of the easiest visual metaphors would be a patch board. Each (system) output would have a "default" option, so new programs/devices would automatically be hooked up to them, but you could also manually grab a "cable" and route an input to an output, or unplug a routed option if you don't want it.

To simplify presentation, by default, things that make sound would be stacked up on the left, devices that consume sound would be stacked on the right, and any plugins could be dragged into the space in the middle to sit between them. "Cables" then run between the sound makers and sound consumers, or from makers to plugins, and plugins to consumers.

This is still going to be a complex system, so definitely not for beginner users, but it would be immensely powerful, and would allow a great deal of flexibility, both for live presentation and for mixing and correction afterwards. For instance, the multi-channel capture would allow for easy editing, removal or replacement of content flagged by ContentID, for instance, having a good clean capture to re-assemble the audio from. For easier control, especially while other things are happening on the system (in a game, for instance) you could have some method to hook up and listen for MIDI control codes, so you can map inputs or outputs to things like the KORG nanoKONTROL2. 

Presentation (Programmatic)

So, how would this appear to programs running? Well, ideally there would be one input and one output (unless more were required, like in OBS' case). Each program would just see a single main and default device to output to, and a single default device to input from, and the engine would handle routing sources appropriately. The "devices" would accept the best quality option available (multi-channel, bitrate, and frequency) and internally the audio data would be converted as needed (Mono microphones upmixed to stereo, 7.1 audio downmixed to stereo for headphones etc.)

Potential Problems

The main hurdle here would be getting the audio out of Windows before it mixes it internally, as this system would have to bypass most of the internals of the Windows sound system, and presenting a unique audio feed to each listening program. I am unfamiliar with the internal workings of Windows Audio, but if programs like OBS can capture audio from a specific program it seems to me there must be a method to do so, even if it's making a "dummy" device that throws away any audio data it gets from Windows and hooking into programs themselves.

Conclusions

This would be a fantastic idea, and I'd love to see it implemented, but I cannot do it personally - It's coding on a much lower level than I've done before, involves hooking into the deep and arcane wizardry of the Windows audio subsystem which I haven't even looked at let alone touched, and is frankly way beyond me. But it's a good idea IMHO, and I'm sure someone could make a small fortune making it or something like it. I frankly wouldn't be surprised if someone has already made something like this, and if they have I'd love to know about it.

Meanwhile, feel free to use this idea to make the next killer audio app, and when you do just chuck my name in the credits somewhere. :D

Friday, September 24, 2021

The EU and device plug mandates

 Okay, so I'm hearing a lot of people grumbling about the EU's proposed new ruling to make devices (like phones, tablets and the like) all use USB-C. There's a lot of grumbling that it's "bad for innovation" (Thanks Apple for that one), and that maybe the UK had the right idea with Brexit, getting out from under these onerous regulations.

See, here's the thing, the EU started this crusade back in 2009. Then they had a "Memorandum of Understanding" signed by the main players in the mobile market (including Apple) that all the manufacturers would agree on a single standard for their devices, and stick to it. That way you wouldn't have to throw away chargers and cables every time you bought a new device, and as mobile devices were seen as more "disposable" than other devices (the whole "carrying around, getting used and worn every day" was what they were going with, more than "new model with new features coming out every so often") this would both reduce waste, mean consumers didn't have to buy a new charger and cable every time (even if it's included in the box, you're still paying for it), and promote innovation as third parties would only have to build for a single connector and it'd work with everything.

Back in 2009, the mobile space was vastly different, with a whole swath of connectors in use at the time, from Nokia's barrel plug and proprietary contact strip, to Sony Ericsson's clip-in connector, Apple's 30-pin dock connector and the various options (Mini-USB, Micro-USB, almost-but-not-quite Mini/Micro USB) being used by the new Android phones.

Most manufacturers quickly moved to standardize on the Micro-USB standard, as it was versatile enough through standards like OTG and MHL, could deliver enough power with USB2.0 (500mA, way up from the lowly 125mA that USB1.0 dictated), had the necessary insertion rigidity to be used for a few years. One notable exception to this was Apple, who elected to ditch their existing 30-pin dock connector, and instead make another proprietary and unlicensable "lightning" connector, with the minor fig leaf that users in the EU would get an Apple Lightning to Micro USB cable bundled with their phones and tablets.

When standards moved on, and the much more capable USB-C standard was ratified, other manufacturers quickly jumped on it, as it was much more capable with features like Power Delivery for much faster charging (and higher charging rates), massively increased bandwidth and better support for extended capabilities like DisplayPort and Thunderbolt. It's increased mechanical strength, bidirectional nature and expandability quickly overshadowed Apple's Lightning connector, and in some cases (notably their laptop line) Apple also switched to using it, but for their mobile devices Apple still held out.

So now, the EU has decided, since the manufacturers won't come together on a standard on their own, like they were supposed to, and like 90% of the manufacturers have, they'll step in and force them all to play ball, levelling the playing field and letting add-on manufacturers (for example) finally be able to innovate, rather than having to support 2 separate and disjointed systems.

Apple knew this was coming, and could have switched to USB-C at any time. They didn't, because they wanted to maintain their stranglehold (and revenue stream) on dongles and adaptors to fit their devices. Anyone who implements part of the Lightning protocol has to pay a usage fee to Apple, of course, which is also why there's no multi-function Apple dongles (unlike USB-C dongles/docks, which have a variety of configurations to suit all needs). Their claims it will "stifle innovation" pale in comparison to the locking down they've done to their own devices and ecosystem, and if they had gone along with the Memorandum of Understanding they signed to in 2009, there wouldn't need to be a codified standard. I am sure at some point in the future a better connector than USB-C will come along, and had Apple kept up their end of the agreement they signed, they would get to be a part of implementing and using that newer standard.

Apple made this bed, and now the EU is going to force them to lay in it. And I, for one, am very glad to see them getting some consequences for their actions. I'm sure the fleet of Apple masticators out there will try and cry foul, that they're just some small company that doesn't deserve to have the weight of the EU coming down on them, or some other such nonsense. Sorry, but I have absolutely no sympathy for them.

As for the whole "Maybe the UK is right with Brexit" nonsense, entirely aside from my thoughts on the matter (which are lengthy, and not at all right for this post), if you want to sell to the EU, the products you are selling have to abide by the EU's rules. As part of the EU, you get to be a part in making those rules, get to have a say in what's in them and what isn't. Outside the EU, you get absolutely no say in what they are or how they apply.

Tuesday, January 29, 2019

What I want from a CMS

Okay, I know I'm probably asking a lot, but this is my list of "want"s for a CMS.

Online Editing

Yup, I want a way to edit the site through a simple web interface. I know a lot of CMS' have this, and this would seem to be the easiest thing to get, but just bear with me.

Static File storage

I'd love for the system to be as fast and lightweight as possible. To the point that there's no need for processing when serving the site. So render it to flat files in the backend, and serve it using something simple and quick like nginx, or a simple CDN. And the static file system can be on a separate host to the admin area, for more security and less processor usage. Plenty of those "headless" systems, right?

Simple, included templating

I would really love it if this system had freely usable templates ready and built out of the box. No need to build your own site around some provided API. Set it and go, with the option for simple customizability later.

Modular design

Want to add functionality? Can do! A nice API lets you drop in modules.

eCommerce

Hey, guess what? I want it all, and that means I want eCommerce capability too. And this leads to the real problem - How do you make a storefront with only flat files?

So here's how I see it working.

The site is all flat, static files, but the optional eCommerce section runs off a tiny active shim (using something lightweight like node.js, Ruby/Rails, Go or python), loaded through JavaScript (or other means, detailed below).

When you initially visit the site, when all the static pages are loaded, one of the items loaded is a lazy-loaded script/JSON call to the eCommerce shim, establishing a session and generating an empty basket for you (or this step could be skipped entirely, with the server-side basket only being created when an item is put into it). This is then stored on the client (cookies, localstorage, webworkers, something similar). Every time you modify your basket, the eCommerce shim is updated to add/remove/alter the contents, ensuring the two are always in-sync (and verifying the details of the client-stored basket, to stop people giving themselves a discount). When the time comes for checkout, the pages are generated for the process by the shim, taking you through the necessary steps until the transaction is complete.

If the user has JavaScript disabled, the "contents of your basket" header section are instead rendered as simple HTML in an iframe from the shim, with the management being done through simple links to the shim (which then redirect to the static page required after the processing is done), and things like the basket display and editing being rendered through iframes.

Why do it this way?

It would make the site a lot simpler, and faster. Database hits would be next to none, as the vast majority of the site is static, so it could be hosted from anywhere, even a simple replicated CDN. The admin system could be hosted on a local network/intranet for security, and wouldn't have to be hosted anywhere near the main site, pushing updates to the CDN as necessary. The eCommerce shim would be lightweight, only called upon when it was needed, and allowing for simple scaling out if demand is particularly high. The system is client agnostic, working equally well on desktop and mobile, with fallbacks for situations where functionality is unsupported, including the capability of disabling completely.

It also means the site is dirt cheap to host, with a basic CDN taking most of the workload. CPU load is low, as content is static, and the static host is as framework agnostic as can be (as it doesn't require any framework, just the capability to serve static HTML). Compressibility is high, and everything can be cached without issue. The shim can be hosted in a simple system agnostic container (and automatically scaled both up to multiple containers, and back down again, as load dictates).

So what are the options?

Right now, as I see it, there are none that work this way. There are a lot of full-fat CMS'  (Wordpress/Joomla/Drupal) that try to host everything inside, making server load heavy. There are some lighter CMS' more meant for blogging (Ghost) that don't even try to touch the eCommerce side. Finally there are "Headless" CMS' that provide an admin interface (sometimes) and an API for you to write into your own site. And right now, none of these are anywhere near what I want. And unfortunately I think that means I might have to write my own. I'd really rather not, and if anyone has already invented this particular wheel (or has a good starting point for me to work from), I'd love to hear about it.

Wednesday, September 5, 2018

Inventing some virtual friends for our robot overlords

For quite a while now, I've been writing a Twitch.tv bot, that will sit in channels it's been invited into and perform some basic housekeeping tasks (dealing with spammers, keeping track of gifts, subscriptions and follows, rolling dice, notifying what channels are live and when the last time someone said something, things like that). This is all well and good, but I need something to test it against. I don't want to put in-development code into a live channel, and I don't have access (personally) to some of the features I want to code for (subscriptions and the like - that would get expensive, fast!).

So, I'm writing a kind of "test harness". It's a node.js program that will sit and wait for websocket connections. When it gets a connection, it behaves like a real twitch.tv instance, letting you log into channels, and populating those channels with "people", moderators, chatters, spammers, staff and so on. Those "people" will talk away to each other, will timeout or ban people, purchase subs (including gift subs and multi-gift subs), join, part, things like that. It won't (currently, and for the foreseeable future) do any of the web APIs, PubSub or Web Push, as that would essentially require me to re-write the entire of Twitch's backend, but this will give me something to test against, at least.

I'm wondering, however, if this will be useful for anyone else. I know other people are building twitch bots, and this will be platform agnostic (It doesn't matter what you're developing on, this little service will appear the same). And ideally when your bot is done, you just change the connection from "localhost" to "irc-ws.chat.twitch.tv" and everything just works.

Monday, August 27, 2018

New update, hot off the presses!

Wow, am I ever bad at this, huh?
Well, thanks to my MSDN/VS subscription expiring (and MS Azure finally noticing) the VM I was using to host ghost_of_leg_bot has gone away, and it's now running on my local network. To add to that, the domain ghostoflegbot.website is going to expire in about 2 weeks, and I don't have the fund necessary to renew it (Donations welcome:
). I am also working on leg_bot v2 (Current working codename "Bipedal Bot"), which is coming along. Still need to get management, follows and preference editing working, so maybe I'll be posting more about that as time goes by.

Wednesday, October 14, 2015

I want to sleep, but my mind won't shut up.

It's far too late, but my mind won't stop. And, as I have nothing better to do, and nowhere else to put it, I might as well cast my words into the void. Here's hoping this helps. I have no idea what I'm going to do with it, but apparently I need to get it down.

Trigger warning: 20 tonnes of concentrated, dehydrated shit, in a 10lb bag.

I. Am. Not. Okay.

It's a simple little lie. Someone asks "How are you?" and I reply "Oh, just fine". I'm really not. I'm a fucking mess, but I know they don't really want to hear it, and I really don't want to tell them. Telling them means acknowledging it, making it real. If I can just make everyone believe everything's fine, it'll all be perfect, right? And I'm good at lying, apparently.

I live in a house that looks like a bomb's hit it, and smells worse, and it's entirely my own fault. I am overweight and lazy and so apathetic about everything, because it doesn't make a difference. I have been living here for 6 years now, and am an illegal alien in this country. I can't work, I can't do anything, and if I get sick or hurt, I can't get any kind of coverage. The paperwork to get me legal has been filled out (at least, my half of it), but it's not been filed yet. Why? Apathy. It's a stupid amount of paperwork that has to be completed and verified, and it's not a guarantee of anything. And processing will take from 2-3 years. The fees have been paid, but wether they still have record of that or not is anybody's guess. And there's really no good reason for it, at all.

My wife, Deb, is working her ass off in retail once again, and her wage is almost good enough for us to survive on. Almost. We're not quite up to our eyebrows in debt, but they are calling, and we are occasionally having to rob Peter to pay Paul, as the saying goes. Deb is working hard, and stressed to the nines, exhausted and weary, physically and emotionally, every single day. She needs me to be her rock, that stalwart companion she can stand with and shelter from the world, and I can be that for her. I can give that impression, sure. She knows things aren't going well for me, she feels I might be a little bit depressed.

I spend every day distracting myself. I watch porn. I play videogames, badly, on easy, while sitting in an empty TeamSpeak server, and stream them to a Twitch channel that nobody watches. I write contributions to a bot and host it, just to get a little recognition. Some days it feels like I am a non-entity. If I was struck by lightning tomorrow, I can count on two hands, maybe three if I'm generous, the number of people who would notice and care. My family is 5,000 miles away, and I feel every inch of that distance some days. I have two or three friends. I act as someone else online, because I know nobody would want to know, would really care, about the real me underneath. I'm just not that interesting, not that important. Duller than dishwater.

I worry for Deb. Her health is not that good, but I can't do anything about that. She is stressing over money, as am I, and I can't do anything about that either. I can't bring money into the house to help with bills because I am currently unemployable. All I have that is in any way nice is a matter of charity or pity. I have $0 to my name, and that's not likely to change in the future. I want to be able to do something. Anything. I want to have a life, I want to make a difference. I want to be somebody, but right now all I'm doing is taking up space. I don't feel, I can't feel. Because if I do, I'm going to feel all of this shit, and it's going to overwhelm me, it's going to break me, and I can't be broken. I can't go anywhere, I can't do anything. I can't even leave, because we can't afford the funery expenses, and besides which I would never do that to Deb. I love her too much to put her through that.

And, most of all, it hurts. Deb is questioning if I actually care. I do. So very much. I care about all this shit. I want to do something, I *NEED* to do something, but I can't. Because it's too big, it's too much. I can't break it into small, bite-sized pieces and deal with it, because it's all intertwined, it's one solid lump. So I push it away, push it aside. I don't let it affect me, don't let it in.

So many things, so many ways, have I found to distract myself from dealing with this crap. And each time I've burned out. I'm burned out on life, and my brain won't let it go, won't let me sleep.

My shoes are too tight. But it doesn't matter, because I have forgotten how to dance.

And writing all this down, casting it into the ether like this? It does nothing. It doesn't help, it doesn't make a fucking ounce of difference, not a single god-damned thing. But at least my mind has quietened a little. Perhaps now I can sleep.

Thursday, July 23, 2015

Leg_Bot

Ghost_of_Leg_Bot is now dead.

Thanks to Twitch API changes, leg_bot will need an almost complete rewrite to continue working. As nobody's using the service anyway, I'm abandoning it. If you want to pick it up and work on it, the source is up on github, and if you'd like the database for the quotes or stats, drop me an e-mail.

The Ghost of Leg_Bot sent me here! What's the deal?

Well, since ufokraana elected to abandon leg_bot, and as there was evidently a need for it, I, Anaerin, have elected to update and host the bot, under the new name "Ghost_of_Leg_Bot". It's database is the final snapshot that ufokraana posted, so all your statistics and the like should still be in place.

That's cool... What about the Web API?

Well, as there's a new host, there's a new URL. currently, the web interface can be found at https://ghostoflegbot.tk - which, incidentally, is where the API can also be found for on-stream counters. The website there will be re-skinned (eventually), but for now it's a direct copy of the old site.
Update! The URL has been changed (and is reflected above). Old links will still work, however.

Isn't Leg_Bot open source?

I believe so. And I have had to make (more than) a few changes to it (to keep up-to-date with changes to the node.js library 'sequelize', as well as adding features detailed below). So I have done what any responsible open-source developer should do: Forked the repo, and am publishing my changes on GitHub.

So how are you hosting it?

The Ghost_of_Leg_Bot is currently residing on a Windows Azure Virtual machine. If you would like to donate towards it's continued upkeep, feel free to drop me a tip.

What new features are there? 

Yes, that's right, new features too!

Dynamic Counters

Counters are now dynamic - any mod can use the counter commands
  • !counter add <command> "<single>" "<plural>"
  • !counter remove <command>
to add and remove counters. Note, when a counter is removed, all the statistics logged for that counter are removed as well.
For example:

!counter add butt "butt" "butts"
!counter add warcrime "incident of friendly fire" "acts of incidental genocide"
!counter remove butt

Keep-Alive

The connection is now automatically set to keep alive, which should help with (some of) twitch's twitchiness.

Anti-Spam

The anti-spam system is now in place. If the bot is in your room, and set as mod, it'll do it's best to apply it's anti-spam rules. If anything matches, it'll timeout the user in question on a sliding scale: 4^numtimeouts. So, 1, 4, 16, 64... seconds.

Dynamic joining and parting

What's that? You want the bot in your channel? Well, there's no longer a need to hassle me - just join it's channel (ghost_of_leg_bot) and say !join. It will then join your room and start doing it's magic. If it's in your room, and you don't want it cluttering your chat with it's spam anymore, join it's channel and tell it !part, and it will leave.

Calendar Watching

On the fanstreamer calendar, but not gotten ghost_of_leg_bot in your channel? It's okay, ghost_of_leg_bot will now watch for twitch updates from any stream mentioned in the calendar. It won't join their channels, but it will be watching twitch, so you can be represented in it's !live report, and on the live page.

Statistics, by Game and by Channel

We keep track of a lot of stats. Now you can see what we keep track of, by game or by channel, at http://ghostoflegbot.tk/stats

Advice editing 

There's a lot of advice in the ghost_of_leg_bot, and not all of it is good advice. Help separate the wheat from the chaff, and vote on the advice ghost_of_leg_bot dispenses at http://ghostoflegbot.tk/advice

Barks

Got a message you find yourself often repeating? Have something you'd like said every so often? Try barks!

  • !bark add <command> "<message>" <Mod only (true or false)> [Interval (optional, in minutes)]
  • !bark remove <command>
For example:

!bark add promo "Check out my donation page at https://streamtip.com/t/anaerin" false
!bark add modsonly "This message can only be triggered by mods" true
!bark add motd "Message of the day, repeats every hour" false 60
!bark add butt "Mods are away, post butts!" false
!bark remove butt

Note: For technical reasons, editing your barks will re-set the timers of any intervals, as will ghost_of_leg_bot's connection derping for some reason.

Also, barks can now be triggered from the API: "http://ghostoflegbot.tk/api/channel/<channel name>/barks/<bark name>" Use this to give your "thanks/support/patreon etc" messages when you bring up your ending screen.

Whispers

Yes, Ghost_of_Leg_Bot now supports whispers. Error messages will be sent via whisper, and if the whisper fails for some reason it'll do it's best to find where you are and notice you there instead. To ensure whispers get through, make sure you follow the bot.

Some commands also work through whispers (those that aren't dependent on a channel), so mostly the basic ones, !nextfan and !nextlrr and !live.

Dice Rolling

Yeah, ghost_of_leg_bot does dice rolling too. Just type !roll and a D&D-style dice roll, and it will report the result to you. For example, "!roll 2d20" might get you the response "Rolled 2d20 and got 20 (1,19)"

Websockets

For those of you with an overlay, especially one in HTML (And if you don't have one, may I recommend this set of JavaScript building blocks as a starting point?) ghost_of_leg_bot now supports websockets. Simply connect a websocket to ws://ghostoflegbot.tk/ws/<channel> (For example, ws://ghostoflegbot.tk/ws/anaerin) and you will get notifications when the game changes and when stats change. For example:

{action: 'GameChanged', game: 'Creative'}
{action: 'StatChanged', stat: 'death', value: 20}
{action: 'GameChanged', game: ''}

This should help updates to the overlay come a lot faster, helping chat interactions somewhat.

Seen Tracking

Want to know when the last time someone spoke, or did something, in ghost_of_leg_bot's purview? Ask it!
!seen Anaerin

Quotes

You asked for it, so quotes are now available. (Currently disabled for cantwearhats and hpbraincase, as they have their own quote-supporting bots):
  • !quote
Returns a random quote.
  • !quote count
Returns the number of quotes available.
  • !quote <number>
Returns the specified quote. For example:
!quote 3
  • !quote bytext <search string>
Searches the quotes for something with "<Search String>" in it, and returns a random matching result. For example:
!quote bytext flying monkeys
  • !quote byauthor <author name>
Searches for quotes written by <author name> and returns a random result. For example:
!quote byauthor senstaku
  • !quote bygame <game name>
Searches for quotes that took place while <game name> was playing and returns a random result. For example:
!quote bygame Batman Arkham City
  • !quote bychannel <channel name>
Searches for quotes that too place in <channel name> and returns a random result. For example:
!quote bychannel admiralmemo
  • !quote bydate <date>
Searches for quotes logged on <date> and returns them. Note: Timezones are a thing. For example:
!quote bydate 2016-03-11
  • !quote add <quote> (author) [date]
MOD ONLY - Adds a quote to the database, returning the ID on a successful add. If the author is not specified, it is assumed to be the person logging the quote, if the date is not specified, it is assumed to be now.
For example:
!quote add This is how quotes work (Anaerin) [2016-03-11]
!quote add Not everything has to be specified [2016-03-12]
!quote add In fact, you can leave everything out.
  • !quote mod <ID> <quote> (author) [date]
MOD ONLY - Modifies quote # ID. If the Author or Date are not specified, they are not changed.
For example:
!quote mod 2 Now quote 2 has other things (Anaerin) [2016-03-11]
!quote mod 7 You can leave those other arguments off, too.
!quote mod 3 But you must have the ID and the quote text.
  • !quote del <id>
MOD ONLY - Removes quote #ID from the database. For example:
!quote del 6
  • !quote <search term>
Attempts to do an "intelligent" search, returning a random result where the text, author or game match the specified term. For example: !quote batman

AWS Support

Support for the new AWS cluster is in testing right now. Hopefully it's stable enough to use.