-
About what I'm about to post ...
09/12/2020 at 14:46 • 1 commentPREFACE TO POSTING SOME NEW PROJECTS
OK, it's been a long time since I updated this project log. Once again, THIS "rPi bare metal vGuitar" project is the overall project that encompasses all the other projects that I have on hackaday. Even if it's not immediately apparent to the casual reader how they all relate, the other projects, including the 3D printer, synth box, experiments with accelerometers, and even the ws2812B switch array, are all related to my efforts to produce an rPi based, bare metal, vGuitar rig.In my last log, from Nov 2019, I said I needed to create a "proof of concept" Looper based on the rPi/circle bare metal code that I have labored on. Now, 10 months later, I have very nearly done that to a level that is demonstrable, and hope, in the next few weeks, to not only post that to Hackaday, but to also record a song (make a youtube "performance" video), along with a "making of" video, that will show some of the various pieces of this super-project "put together" in a working floor rig.
But before I do that, I will need to post a couple of (at least one) other sub-project(s) that have taken place since my last Log entry, and the reason for this entry is to provide some context for those projects, and to "tell the story" behind them.
A WORD ON THE DEVELOPMENT ENVIRONMENT
I think the purport of this project may get lost sometimes. The point is that others can, if they wish, build these projects. But to do that, you need to at least briefly understand the development environment.
The Circle and additional code that I have developed for the Raspberry Pi is a bare metal development environment loosely based on the Arduino development environment. I do all of my development on a Windows based machine. Windows 10 at this time. You don't have to, and this code should work on Linux, for example, but I use Windows.
I assume that the reader can install the Arduino devenv, and add the publicly available Teensy support. With that, and the gnu arm-none-eabi compiler, and perhaps a particular version of gnu make, basically you should be able to build my example Circle projects, and worst case, stick the resulting kernel7.img onto a bootable rPi SD card and boot up the app.
Everyone has their own preferences and development environments.
I really don't like the whole world of hyper-integrated IDE's that we have grown into, like the MS Visual Development Environment or the Android IDE. They are slow, and klunky, and force unimaginably complex architectures and directory structures on the projects and development thought processes. I don't want to run Linux on my "main" personal machine, which is also (always going to be) my main development machine. I didn't even want to run Linux on the project platform lol ... the whole point of the "bare metal" approach is to get away from "do everything for everybody" operating systems, and the complexity involved with them, and get back to something where it is somewhat reasonable for a single person to understand the entire deployment environment, as well as to be able to build it in seconds, versus hours. I don't want to do linux builds, or friggin learn how to write a general purpose driver for the whole world. I just want the sound card to work in my dedicated audio application, lol, and I wanna know HOW it is working.
Don't even get me started on Apple. You can't even develop and test an IOS app without years worth of systems growth, subscribing to services, buying a MacBook, submitting your app for approval, and somehow getting it ONTO a frigging iPad. If it was easier, perhaps this whole project would not be taking place. But Apple is the worst of em when it comes to proprietary black box dependencies and complexities. And most "mobile" apps these days absolutely suck in terms of learnability. Nothing like having to press an odd button to see what it does in order to learn how a program works. Heck, I've downloaded Apps and can't even figure out what they're supposed to be trying to accomplish. No words. No instructions. No consistency. Big round yellow buttons. What is that?
So my code is just straight C++. Open Source and compiled by GNU. Stuck on a SD card, which runs in an rPi.
I'm also an old-school Perl hacker. I still find it an amazing language in terms of pulling together disparate pieces of junk and making something that runs. So this is one place I will probably diverge from most readers, but I want to describe a few other things in my development environment that are related to my 30+ year Perl history.
First of all, I just use a pretty simple Text Editor as the basic core of my personal IDE .... I use an old copy of KOMODO, from Activestate, and the associated Perl distribution that is/was available from them at some point.
...
Then I stick a Teensy between the Windows machine and the rPi.
...I wrote a "putty-like" Windows console application in Perl, that deals with com ports, works with the Arduino IDE (to disconnect the comm ports while building, supports Ansi color codes, and contains protocols to upload, through the teensy, built kernel images (among other things) to the rPi. After editing a bunch of stuff, a single keystroke in Komodo kicks off the "make", and a javascript script that I wrote for Komodo tells the console application that a file needs to be sent to the rPi. The console application can tell the teensy to reboot the rPi, and when it reboots, it comes up in my "bootloader" for 3 seconds (before loading whatever kernel is on the SD card). The console application sees this, and uploads the new kernel to the bootloader, which then tells the rPi to do a "soft boot" (just start running the new kernel that was uploaded directly in memory). The kernel is also (by a "define" in the bootloader C++ code) written to the SD card ... so a subsequent reboot will boot the newly installed kernel..
Thus I don't ever swap the SD card out of the rPi (except when I have to work on the bootloader itself).
This all works with (javascript scripts written in) Komodo, which calls "make" to do various builds, and notices when something has been built which should be downloaded to the rPi. This console program "knows" about the teensy-rPi relationship and communicates to the rPi via the Teensy. Everybody gets their own "color" for messages coming in, or going out, over the serial port, so I can tell what's happening. The teensy can also reboot the rPi, and I can tell the rPi, via the console program, to do that with "ctrl-B' on my windows machine.
Why am I saying all this.
Because the devleopment environment context might be useful to understanding or reproducing this project. And it goes to the hardware architecture (or why there's a teensy in my rPi box).
USB MIDI and HID DEVICES suck!
So after my Nov 2019 post, I did, in fact, develop a rudimentary Looper. That required developing an event driven windowing system for Circle which took quite a bit of time. So then I had a mouse and windows thing running on my 40" HDMI T.V. Then I added a rudimentary USB MIDI event handling system, implementing controls for audio devices (things like a VU meter, volume control sliders, etc) that actually work, so that I could hook up some external MIDI devices to control the looper.
That's where I began to run into problems and the project took a fairly serious multi-month step in a different direction.
I started running into intermittent failures, crashes, or just noise in the system when using USB Midi devices (or a USB mouse).
A word about rPi sound cards. The best sounding, as well as the most powerful, sound card I have is the AudioInjector Octo 6-in, 8-out sound card. I have implemented 2-3 other sound cards in this code, including the AudioInjector Stereo, the Teensy audio card, and a HiFiBerry (or whatever it's called), and the Octo is the quietest of them. It is also the most CPU intensive, inasmuch as the I2S bandwitdth used is actually a full 8 channel pseudo TDM format . So the system is actually processing 8 channels of input data into 8 channels of output data, even though I am only using two of them (stereo) in this rudimentary Looper.
And yet the latency of the system is just right at 6ms ... which I am happy with and determined to keep.
But, for whatever reason, I found that, in the current code, the use of USB within Circle negatively affects the audio performance
USB Midi SUCKS. Every USB Midi Device has to be POLLED (by the USB controller) at least 500 times a second! Same for USB HID devices. Polled! The USB (MIDI) architecture is the opposite of interrupt driven! I guess "mature operating systems" like Windows can handle this load due to many years of optimization work, but the Circle environment appears to create some conflicts, at least with my implementation of I2S audio (the port of the Teensy Audio library to this Circle bare metal rPi environment) and the 2835 BCM/PCM.
EVEN though I am, in bare metal, utilizing the mutli-core rPi 3B+ .... Core 0 is dedicated to handling interrupts ... no code, per se, "runs" on it, only interrupt handlers. Core 1 is dedicated to the audio system, Core 2 is dedicated to the UI, and Core3 is currently unused (somewhat used for debugging probes). When Core0 receives an I2S (DMA) interrupt, it sets up to read or write the next buffer via DMA, and passes the current buffer to Core1 via an inter-processor interrupt. That's it. Core1 then has the maximum chance to do what it can in the 30ms window per buffer (128 sample buffers at 44.1 Khz), which is where the "Looper" is implemented..
I found that if I use the mouse, or a USB midi device, that either (a) the program starts crashing intermittently, or (b) I start getting a bunch of noise in the audio buffers. And none of it was for any "apparent" reason that I could suss out. I spent almost a month trying to figure out what the heck the problem was, and came very close to canning this whole project. Seriously, I was about to throw away 1.5 years of development effort here.
I was like, WTF don't I just write this for linux on the rPi, like everybody else?But that little devil was in my ear. He said "yeah, well you know you won't even be able to get the driver for the Octo to work reliably in Linux, and in the end, you'll have the same issue, but additional mountains, literal planetary masses, of code to sort through and question in the process" .....
So, I decided to blow off USB Midi (and USB HID device) support.
The Looper worked pretty well over the serial port (to the Teensy to the rPi). I'll figure something out.
HENCE THE TEENSY EXPRESSION MIDI PEDAL
Thus I ended up going off in yet another direction for a couple of months, culminating in the production of the Teensy Expression MIDI controller project, which I hope to post today.
Huh? I thought you just said that USB Midi was the root of all evil!
Yes, well, ahem, after my initial knee jerk thought to just create some kind of a switch-controller array for the "Looper" (teensy/rPi) thing, as I started really thinking about making a floor controller, and I started working with the teensy3.6, and one thing led to another.
I mean, it's really easy to make a teensy3.6 based MIDI controller. And I will need expression pedals, right? And wow, look, I can host a USB device as well, like the Fishman FTP dongle, and continue reverse engineering and understanding that. So I spent quite a bit of time experimenting with, and developing stuff completely unrelated to the Looper ... not the least of which was to implement the USB Host capability on the teensy3.6 and do some serious reverse engineering of the Fishman FTP (Triple Play) MIDI protocols.
And since I've gone that far, might as well make it so that it can be EITHER a USB midi device, or (communicating via Serial data) a dedicated controller for this rudimentary "proof-of-concept" Looper thing.
So the TeensyEpression sub-project grew into it's own semi-huge thing, that actually WORKS with my current gig-rig, allows me to experiment with that, while at the same time, being able to be used as a controller (via serial data) for this rudimentary Looper project.
So, that project has to get posted. I hope to post it today.
There was also some interesting experimentation into continuous controllers that I am continuing and not revealing at this time, but I am very excited about!
CROSSFADE NEEDED
Then (actually before, and at the same time as I was almost giving up on this whole mess) I realized that my rudimentary Looper was ... uhm ... TOO rudimentary.
It basically worked well at recording clips of time and playing them back, and if you just count "one two three four" into a microphone, you get nice loops. But in actual use, like looping a guitar, or for test purposes, a continuous human voice, anything that crosses a loop boundary produces really noticeable "clicks" and other sonic artifacts.
I determined I needed to implement "cross-fades" between the ends, and beginnings of loops.
So, that took some time. It was significantly complex to change the way I did everything in handing, recording, and playing back clips to provide cross-fading between clips. Not the least of which was that, in my mind, to do it "right" you need to record MORE than the "user designated loop length". Let's say I want a 30 ms cross fade. That means that I have to record an EXTRA 30ms AFTER the loop, WHILE (in certain circumstances) starting to play the clip I am recording, back at the start, from beginning. Thus I need to create, and maintain, two pointers into a given sound clip, and the resultant state machine is significantly more complex than the previous one.
More notes on that in the Looper project itself, but lets just say that added another bunch of time to the project.
END OF THIS LOG REPORT
It has been a tough year. With the virus and everything, there have also been more than the usual amount of personal and work related issues over the last year. It has been hard to make consistent progress on the project, and harder even still to find the time, and motivation, to post here on Hackaday, about it.
But I preserver. I hope to be posting at least one or two projects in the "now" time-frame here on Hackaday, as I also project being able to hopefully be able to post the Looper project, as well as use it in some YouTube videos, in the next couple of weeks.
And please note that the Looper is only a rudimentary demonstration (though a needed part) of what this system can do.
The 3D printed looper box, which I will be showing you, even though only stereo in this incarnation, with it's rPi, teensy 3.2, and Octo 6x8 sound card, as well as a 7" touch screen, is actually, more or less, a complete development platform for arbitrary 6-in, 8-out audio applications. Guitar effects? Mixer? Synthesizer? All of em?
And note that the hardware (circuit boards, 3D printing stuff) could ALSO be used for any linux based applications that could take advantage of the sound card..
But, finally, to the point, what this project represents is a self contained, from the ground up, platform for developing rPi audio applications in C++, that does not require a linux distribution or a lot of development environment dependencies.
I hope someone besides me thinks this was at least worth some of the effort :-)
That's it for now. Hopefully you will see some new project(s) very soon.
- Patrick
-
So, I need to build a simple “proof of concept” looper at this point
11/05/2019 at 19:30 • 0 commentsI spend a lot of time writing documents to myself. I have several "object oriented" design and architecture documents in the works, that i've started, around this general project.
The main problem is that the project domain extends in so many directions, on so many dimensions, at the same time, that it has become difficult to manage, and that has somewhat affected my motivation to keep pressing forward.
The last few months have seen me mostly playing with 3d printing, and most recently, blowing the dust off of my existing rig in the Synthbox 1 project. In doing so I've been practicing with the old rig, using Quantiloop Pro on the iPad as my looper. In this configuration I keep running into the limitations in that software regarding switching between sequential and parallel looping between songs and adding and controlling layers in sequential loops.
So, I think the next push will be to make a simple proof of concept Looper. This looper *should* be as functional as the existing Quantiloop program and steer away from introducing new paradigms for control and layering except to address the actual issues I am experiencing using said software in actual live gigs.
I envision a 4x4 (four sequences with upto four layers per sequence) looper, possibly with a dedicated designed and printed foot contorller.
Even so, architecturally, from a software perpective, this next step in the project is challenging.
I never said my goals were modest **, and the result is that I have bitten off a tremendous amount to chew. This bare metal v-guitar project, as it stands, has expanded outwards in many different dimensions, and frankly, is becoming difficult to manage. Here are some of my main feelings at this point:
- The "arduino" framework for static initialization of the audio system is an artifice that does not blend well with Circle's run-time creation and initialization of the Kernel. There's a fair chunk of complexity solely related to orchestrating run-time initialization of statically declared objects that could be removed. This paradigm also constricts the ability to create more flexible audio configurations at run time. While appropriate for the Arduino, pre-defining all of the audio connections and routing at compile time may not be the best way to go, moving forward, for this project.
- The goal of creating an event driven windowing system, though fine as it is, and workable for simple applications, itself needs a lot of effort. Additional types of controls (sliders, knobs, and the all important vu-meter) need to be created. Secondly, although I think not a show stopper for dedicated applications, the implementation is not a completely generalized windowing system with regards to clip regions and underlying window updating. It works fine as long as there is only one window, and possibly a dialog up over that, but does not implement clipping and real-time updating of hidden or partially obscured windows. So, for instance, a vu-meter, without kludges, implemented in it, will stop updating if a dialog window is popped up over it, partially obscuring it. A real-world example application might reveal how important, or not, this is. It is an area of the code that I really don't enjoy working on, and I do have concerns that a robust implementation will have performance effects, especially on non-optimized display hardware like cheap touch screens or LED arrays.
- Since I started the project, RST has released another 3rd party add-on UI library that is far better looking than mine or the previously available UGUI. However it suffers both from the same structural flaws as the other Circle provided UI libraries (it is linked directly to the rPi screen and Circle USB mouse/touch devices and is not well generalized to other displays and input devices). This is compounded by the fact that I could not get RST to include base class generalizations to those devices in the upstream codebase. So, if I want to use this I will have to further diverge my Circle codebase from his, which is not a prospect I relish, esp, as for example, he has now come up with rPi4 support, and I have to re-merge all of my changes with his.
- I had only made a fledgling start on the midi/event subsystems that glue everything (the audio system, input devices, and the UI) together. Even for a proof of concept looper I will have to address that and make design commitments with regards to how that's all going to work together.
- The realization, or reminder if you will, that in live performance settings, I really need good feedback, both on a tablet on a music stand, as well as on the floor where I have to look to move my feet, about what the system is doing. To whit, all the ws2812b and display devices explorations and sub-projects. I still have a number of devices, including a very cool 2mm RGB LED array to mess around with that I've not even tested yet. Likewise, I have a nice mounting system (adafruit) for the rPI 7" screen ... still in the box ... that I should break out, even though I do all my development on an large HDMI TV screen. At some point I have to start getting some real world scale into the hardware and get something I can actually put on the floor and test.
- And finally, I still have not completely come down on where I think a Teensy will fit into it, though my gut feeling is that there will be at least one of them in the system. The rPi's GPIO is too limited, and, at a minimum I will need an expression pedal convertor somewhere in the system that uses analog inputs, of which there are none on the rPI. And the Teensy is just so accessible and useful. I *still* toy with the idea (and need to test) using it in a floor controller with a serial interface to the rPI (not necessarily MIDI) and whether I can usefully do that with a 6 or 10 foot serial cable. I have many concerns about Circle's ability to handle multiple simultaneous MIDI devices in the context of the UI and audio processing on the rPI.
Without even getting into the synth or guitar effects parts of the project, a looper seems like the safest, as well as simplest, application that I can move forward on. For testing I can continue to use the iPad synth (Sampletank 3) or even just the straight guitar, as input, as I keep exploring those avenues (including messing around with the Zynthian that I built, and/or building my own guitar effects). I *could* even end up using a commercially availalble guitar effects pefal, like a GR3X effects pedal, with such a proof-of-concept, dedicated, looper, if I wanted to.
And in spite of the fact that I have an AudioInjector Octo (6-in, 8-out) sound card working, it may be too much initial complexity to try to also incorporate the extra dimension of controlling and utilizing multiple inputs and outputs into and out of the looper in a proof-of-concept design. So, I think the initial looper will probably just be stereo-in and stereo-out ... only on the guitar/synth .... not the vocals, or additional inputs like mics on the bongos or steel-pan, like I think could potentially happen, and be really cool, in the future.--------------------------------------
So there you have it. A pep talk to myself. If anyone is following anything I'm talking about, I appreciate and welcome any and all comments and suggestions.
Thanks!
- Patrick
** asterisk :-) .... essentially I am writing an operating system for the rPI. Not really where I thought I would be after 9-10 months on the project.
-
Moved source to Github ...
09/05/2019 at 00:26 • 0 comments2019-09-04
I have moved the source code for my modifications of Circle to Github.This is after updating, today, to the latest Circle source which supports the rPi 4.
I re-forked the Circle source and re-applied my changes for better upwards compatibility with future releases by rsta.
--------------------------------------------------------------
There are two Github repositories:
https://github.com/phorton1/circle contains my Fork of Circle, with as few changes as I could make to get my stuff to compile and work.
You should be able to clone and build the above completely separately from any of my specific changes, below.
https://github.com/phorton1/circle-prh contains my Additions to Circle. This repository gets cloned to a folder called "_prh" within the above repository.
This change minimizes the amount of work I have to do as rsta provides new updates to Circle.
The previous repository at Bitbucktet has been eliminated.
- Patrick
-
Back to it ...
09/03/2019 at 00:25 • 0 commentsGetting back to the project after a month of playing with 3D printing.
I have cleaned up slightly, recompiled and somewhat tested all the example test programs.
This *might* be an opportunity to grab a copy of this *preliminary* source code.
The "ui" branch and the "4 track recorder" are broken (and obsolete as is).
The next things I want (need) to work on is basically the integration of the UI and Audio systems along with MIDI.
This "triangle" is fundamental. The UI reflects and modifies the state of the audio devices (vu meters, volume controls, etc). As well, The UI should be able to create a generalized MIDI control and the audio devices themselves should react to, and possibly generate MIDI events. I am struggling a bit with "who is in charge" and how to best compartmentalize and factor this functionality.
It also plays into the linking of things.
Although interesting at first, the emulation of the static initialization of the Teensy Library objects (and the Arduino like setup() and loop() methods) is proving to be awkward and constraining. Circle dynamically allocates the kernel, and static initialization of major objects does not fit well with it's model. Furthermore statically creating audio objects means that they cannot be deleted consistently at run-time. This is particularly bad for AudioConnections, but relevant for all the audio objects. A better model, going forward, is that things like connections between audio devices, as well as the audio devices themselves, are entirely created at runtime, allowing for the configuration (audio routing) to be modified more consistently.
Finally, the UI System (wsWindows) is so-so as it is. I have been struggling to avoid the complexity of a true windowing system with a zOrder for all windows objects, with appropriate clipping, so that windows are "updated" and the visible portions are redrawn as necessary even when other windows are popped up over them. It's really complicated to implement and I can't decide how important that behvior is. It is expected from a full blown windowing system, but perhaps may not be needed for this targeted use of the rPI.
So as I get the AudioDevice-MIDI-UI triangle sorted out a bit, I am going to try to rework my old "4 track recorder" example into the new wsWindows environment and see how it feels.
Anyways, just wanted to let you know I'm back on it ...
- Patrick
-
First UI and bare-metal multi-core
06/28/2019 at 04:18 • 0 commentsI have checked in a very rudimentary example-only four track audio recorder based on my versions of the bare metal Circle and ported Teensy Audio libraries. I hacked my way through the Circle addon UGUI library, starting with the Tiny Oscilloscope example, and then adding my own C++ classes, to get a nominally workable windowing system. For the first time I started testing the audio system in conjunction with some sort-of real world capabilities, namely a mouse and HDMI output.
I need to emphasize that this is a very early preliminary proof-of-concept of a small part of what the system can/will do. Most of the code is actually throw-away, as, for example, I will probably write my own event driven windowing system from the ground up. I will not be, on the other hand, hopefully, re-writing the USB stack, which, thanks to rst, seems to work pretty good at this stage.
I spent some time evaluating available GUI’s that I could port to Circle and came away deciding to write my own because of the same reasons I am doing this project in the first place. Yes, it *might* be possible to port GLUT to the OpenGL 3 work that rst has already done, and then to port GTK on top of that, and then to port a windowing system on top of that, yawn. But part of the whole raison d’etre for this project is to get away from huge stacks of complicated arcane software into a simpler C++ framework that a person can easily understand. Linux is what, 3 million lines of code and takes hours and hours to compile. This program, and Circle, are probably on the order of 50,000 lines and compile in less than a minute.
That being said, the UGUI addon is nice and works well for this simple demo, but I realize that I want to build a complete audio oriented event driven windowing system … with things like MIDI and Audio device control messages built in from the ground up, so this code is more or less, as I said, merely a proof of concept and to test things for a while going forwards.
There were a couple of other personal “firsts” in this foray. The bare metal code is capable of running on a single core or on multiple cores. In multiple-core “mode” it runs the audio and USB interrupts on core 0, the audio processing tasks on core 1, and the UI on core 2. It’s nice to know that there is some horsepower in the barn in case I need it (which I will) in the future, even though in single core mode the simple recorder, even with 4 tracks simultaneously, is using less than 1% of the processor time by certain measurements.
This project also allowed me to delve into visualization of the audio … which came in handy, actually, in finding a bug in one of the audio devices (the “tdm” device I use with the Octo). Sometimes it is hard to deal with zillions of bytes flying by on the wire, but a picture immediately shows you glitch.
So there’s that too …
(p.s. sorry for the image quality ... its a photo of my television taken with my phone ... no hdmi capture at this time).
In any case, I feel like I am now nearly in a position to begin designing the actual system. I have a few different Audio cards working and a basic audio library that can efficiently process sound. There are some audio objects and effects that are workable, including reverb, a sine-wave generator, four channel mixer, and so on, that I can play with. I have a rudimentary UI capability and some understanding of how the real windowing system will work. I believe (and will be proving that) I can hook up a variety of different touch screens, from the official 7” rpi screen down to a 2.5” screen that I got. I have a slew of Teensys and Arduinos with which to develop interesting controllers, and I believe that the USB midi is likely to work “out of the box”.
There's obviously still some stuff to do before writing down my ideas about the Architecture and Design of the system, but at this point, I feel pretty good. I, of course, wonder all the time if I should just chuck this effort and switch to linux, but then I start having fun and getting results from the bare-metal and that keeps me going ...
More later ...
-
Pi Circle to Teensy Audio Shield and Quad Audio device
06/19/2019 at 03:12 • 0 commentsI added the AudioControlSGTL5000 object to my port of the Teensy Audio Library. Please see the page at:
https://hackaday.io/page/6335-pi-circle-to-teensy-audio-shield-and-quad-audio-device
-
Circle Fork Source Code
06/16/2019 at 18:06 • 0 commentsWithout further ado, here is a link my Fork of the Circle source code including the work-in-progress on the Circle Teensy Audio Library and my Circle rPi Bootloader, among other things.
https://bitbucket.org/phorton1/src-circle/src/master/
Sorry it's in bitbucket. At some point I will need to move everything to github.
-
Initial Latency Benchmarks
06/16/2019 at 18:02 • 0 commentsI did some initial benchmarks of the latency of the Circle Teensy Audio Library with the Octo 6-in 8 out sound card. At first I was disappointed. With the standard settings of 44.1khz sampling and a 128 sample buffer, the latency was about 9 ms (milliseconds). Though way better than the 38ms I was getting from the iPad setup, I was hoping it would be quicker. I then tried a few things.
- default setup (44.1khz, 128 sample buffer) - 9 ms
- "short circuit" input buffer to output buffer - 6ms
- decrease buffer size to 32 samples - 3 ms
- increase sample rate to 88.2 khs - approx 1.5 ms
The initial measurement represents the output buffer being 3 full buffers behind the input buffer. This sort of makes sense, but I was hoping it would be 6ms.
The first thing I tried was to short circuit my code, using the same buffers for input and output DMA. I had noticed, due to a bug, before, that this worked, though I'm not sure why. By using the same DMA buffers, data is being read into the buffers FROM the sound card simultaneously as it is being transmitted TO the sound card. It just happens to work, I think, because of the order in which I start the DMA's. It is not a valid measurement, because the system is unusable, basically, with no access to the data in this configuration, but it gives me a rough idea of the minimum latency possible at a given sample rate and buffer size. Since each buffer takes about 3ms to transfer, 6ms means that the transmit buffer is 2 full buffers behind the input buffer.
So, I then decreased the buffer size to 32 samples. with a resultant measured latency of 3 ms. I'm not sure if the reverbs will work, but straight through sound worked ok. By the way, the Octo sounds pretty darned good. I cannot hear any artifacts or distortion at any reasonable listening levels. When I decreased the buffer to 32 samples, it continued to work, but, even without short circuiting. The buffers ARE going through the Teensy Audio Library transmit() and update() processes, so this is a usable configuration.
I then tried upping the sample rate to 88.2 khz - which means BCLK is running at 22.4Mhz and LRCLK at abut 704kHz, and it still worked! I was surprised. I'll have to see how it works with real code (i.e. the reverbs), but this brought the latency down to a respectable 1.5 ms.
In my experience anything under about 2ms and we humans think of it as real-time. Although most folks seem to accept "under 10ms" as functional, I am afraid, particularly early in development, about assuming that is sufficient. So I want to ensure that, in the future, if I need to, that the system can be built to a lower latency specification.
-
Audio Injector Octo working with Circle port of Teensy Audio Library
06/13/2019 at 13:58 • 0 commentsGot the 6-in, 8-out, Audio Injector Octo sound card working with my bare metal Circle port of the Teensy Audio Library !! Here's a link to the Audio Injector Forum: forum
(this log entry has been edited to add a picture of the Octo sound card in-vivo, below):
After much consideration, I finally decided about two weeks ago to port Paul's Teensy Audio Library to work with RST's bare metal Circle framework on the rPi. I retain my desire to avoid using linux and the complicated driver layers it presents, His library is far simpler, easier to understand and port, and provides a good basic starting point for doing sound projects.
The initial steps of the port, using the Audio Injector Stereo soundcard, went well as I already had a working bi-directional Circle i2s device written from previous experiments. Within an evening I had the three most basic classes working: AudioInputI2s, AudioOutputI2s, and AudioControlWm8731. After that It only took a few hours to port a couple more interesting example classes including the Mixer and Reverbs. The Mixer ported directly, in 5 minutes, with no source level mods ! To get the reverbs to compile I had to dig up and add some arm-math libraries to Circle, but even that only took a few hours, but they also basically compiled without source level mods..
I even created an arduino-like framework for running the programs within Circle, so the following working source code will look familiar to anyone who has worked with the Teensy Audio Library before. But please understand that the following program is not an Arduino sketch. It runs on an rPI within the Circel bare metal framework!
//----------------------------------------------------------- // reverb_test.cpp #include <Arduino.h> // Arduino.h is not needed but it is fun to list it // here as if it were a real arduino program #include <audio\Audio.h> #define I2S_MASTER 0 #if I2S_MASTER AudioInputI2S input; #else AudioInputI2Sslave input; #endif AudioEffectReverb reverb1; AudioEffectReverb reverb2; AudioMixer4 mixer1; AudioMixer4 mixer2; #if I2S_MASTER AudioOutputI2S output; AudioControlWM8731 control; #else AudioOutputI2Sslave output; AudioControlWM8731master control; #endif AudioConnection c3(input, 0, mixer1, 0); AudioConnection c4(reverb1, 0, mixer1, 1); AudioConnection c5(input, 1, mixer2, 0); AudioConnection c6(reverb2, 0, mixer2, 1); AudioConnection c7(mixer1, 0, output, 0); AudioConnection c8(mixer2, 0, output, 1); void setup() { printf("reverb_test::setup()\n"); reverb1.reverbTime(0.6); reverb2.reverbTime(0.6); AudioMemory(20); control.enable(); control.inputSelect(AUDIO_INPUT_LINEIN); control.inputLevel(1.0); control.volume(1.0); mixer1.gain(0, 0.6); mixer1.gain(1, 0.3); mixer2.gain(0, 0.6); mixer2.gain(1, 0.3); printf("reverb_test::setup() finished\n"); } void loop() { }
I figured it would then be pretty easy to implement the Audio Injector Octo, as Paul already had a ControlCS42448 class in the library.
However, it turns out that the Octo is not really a "standard" CS42448. Flatmax has implemented an FPGA on the board that becomes the BCLK and LRCLK master for both the cs42448 and the rpi i2s (which are both slaves), and it took some digging to figure out how to initialize it and get it working. For better or worse, Flatmax used an additional FIVE gpio pins to communicate with the fpga. One for a reset signal, and four to set a 4 bit sample rate. Although I'm not terribly thrilled with the extra gpio pin usage, and wonder why he did not perhaps just piggyback the fpga control as an additional i2c device on the existing bus, by and large the board is impressive with it's 6 (six) ins and 8 output channels, and sounds pretty clean at 44.1K 16bit.
Below is an image showing the 176KHz LRCLOCK being produced by the Octo card:
I still have some reservations about moving forward with the Teensy Audio Library ... namely that it IS more or less limited (constructed) to 16 bit 44.1K sound, but for the time being it is what I have. I can change that if I really want. I am also still considering porting JACK to the Circle framework, as it *might* provide more compatibility with existing other code (i.e. Zynthian, FluidSynth, etc) that I might want to try to port to the bare metal framework later.
Who knows? :-)
But as of today the Octo works with the Teensy Audio Library on a Circle Bare metal rPi, and that's what I wanted to post.
- Patrick
-
prh - my first Log Entry
05/24/2019 at 18:58 • 1 commentThis is my first project log entry.
(1) Started Hackaday.io pages.
There! That's it. Not really, there's ton's of backdated log entries I want to make, but I'm just getting started with Hackaday and learning to use it. I don;t think the "MOTIVATION" section from my initial "Details" should go here in the Log, but maybe that's a way to get started. All I know is that I have made my first log entry, and this is it.
pressing "Publish" ...