Close
0%
0%

Rubidium 2.0

This is an all in one spectrum and logic analyzer, robotics control platform, and modular synthesizer with audio in and sheet music out!

Similar projects worth following
One of the problems facing the world today, besides the current shortage of components, is a lack of the high quality software tools that are actually needed for building truly useful and innovative projects. Many people want to be able to, at least in principle, "cut the Microsoft apron strings" and get back to an older way of doing things - like analog synths on the one hand, but also having a fresh approach to retro computing projects, like the Apple II or Commodore 64/Amiga reimagined. Wouldn't it be nice to have projects that "just simply work" when you turn them on, without endless updates, bad patch Tuesdays, security breaches. Oh, and the kitchen sink - of course!

 This is a continuation of two previous projects.  "Stalking the Big One" from 2019 which discussed a possible role for a method of detecting premonitory p-waves in forecasting major seismic and volcanic events, along with the parallel development of spectrum analysis algorithms and data acquisition methods for microcontrollers.  A continuation of that project "Computer Motivator" provides and seeks to provide even more improved software tools for microcontrollers, such as improved serial port interfacing code, a LISP-based object processing platform, etc.  Yet many problems continue, for many a would-be hardware hacker.  All one needs to do is look on the Parallax forums, for example, and there are many complaints, in general - and not just concerning Parallax products. 

 Many people would like to be able to use Visual Studio Code to carry out active debugging sessions, and some progress has been made in that direction. Still, the official Parallax tools, as well as the Arduino tools do not provide a TCP listening socket for GDB-style connections, yet Frame Lisp does!  Likewise, there are many complaints about the lack of Linux tools or tools that will run on a tablet such as an Android, or an iPad; even though this should be easy to do using Microsoft's so-called "write once run anywhere" strategy, that is to say, if that "big company with a small name" can get their act together.

Then there is the issue of UNICODE, which along with the hassles of trying to get legacy code to work provides many benefits, that make the efforts well worth it - where appropriate.  That is because not only do we get Emojis, chess fonts, Chinese, Japanese, Mayan, Cherokee, schematic symbols, and so on; but through the use of so-called "Input method editors" (also known as an IME) it is in principle possible to provide improved support for persons with disabilities, as well as everyone in general - that is to say since if an application is IME aware, and you have a suitable third-party product that provides alternative data entry methods, then those pathways should also work with speech recognition, text to speech, and other alternative forms of interacting with the software.  This is something that is, AFAIK all but completely lacking in most of the PC-based tools for Arduino, Propeller, etc.

Of course, if what people really want is a new type of Euro-Rack compatible synthesizer that is also capable of being used as an up to 64-channel logic analyzer and with audio in and sheet music out capabilities, then stay tuned!  Kitchen sink optional.

music_notation1.cpp

This is a quick and dirty piece of C++ that I have put together to plot a page of sheet music in at least some rudimentary, but recognizable form, and which will be used with to capture and display data generated by "logarithmic" real time spectrum analyzer, i.e., as an alternative way of viewing audio data. Copyright 2021 Gerold Lee Gorman. MIT/GNU/LGPL license. Enjoy!

plain - 5.84 kB - 10/27/2021 at 12:06

Download

music_notation_test.pdf

Quick test of the music notation printing capability that I am adding to the C++ build of the Propeller Debug Terminal for use when working with spectrum analyzer modes.

Adobe Portable Document Format - 80.91 kB - 10/26/2021 at 08:48

Preview
Download

declaration1.cpp

This is a C++ port of the Pascal "procedure" DECLARATIONPART from the UCSD Pascal p-system. Please see the release notes provided by the University of California, San Diego, for licensing information and permissions with respect to the original Pascal source. Please note that you WIILL NOT be able to get this to compile AND run without the correct C++ header files, among other things. Snake Oil, Smoke and Mirrors, etc. optional.

plain - 34.84 kB - 10/21/2021 at 11:46

Download

calculator_test.h

This is the header file for the backend of a simple calculator application, which is being used to demonstrate and develop techniques for creating an emulated (or simulated) CPU/ALU/FPU. See the project logs for further details. Copyright 2021 Gerold Lee Gorman. This is free software made available under the GNU/MIT/LGPL compiler or library licenses.

plain - 591.00 bytes - 10/16/2021 at 12:25

Download

calculator_test.cpp

This is the current C++ source code for simulating an FPU (floating point unit) which is an extension of the fake_cpu project, which in turn demonstrates how it is possible to implement an ALU which uses nothing but NOR gates in its operation.

plain - 5.90 kB - 10/16/2021 at 12:22

Download

View all 7 files

  • 1 × Parallax Propeller EVAL board Rev B/C.
  • 1 × Suitable case according to desired configuration
  • 1 × Knobs, jacks, potentiometers, cables, etc.
  • 1 × Kitchen Sink (optional)
  • 1 × Software development tools, such as Visual Studio or Visual Studio Code, and/or other optional third party tools.

View all 6 components

  • All that Glitters

    glgorman10/27/2021 at 11:47 0 comments

    Streaming hexadecimal data from the P2 Eval board which uses multiple DAC and ADC pins to generate various waveforms, which are being converted to analog and back, and then streamed at 2 Mbits/sec over USB to the application, which now has a "sheet music" style display which will be used to take a log-log plot of spectrum analyzer data which will (more or less) pick out any new peaks in each newly rendered frame.  Lots of work still remains, like Having BPM detection would be nice, but is not a requirement, as BPM can simply be entered via a menu, so as to be able to get things running.  For example, as I demonstrated earlier, I showed how Bohemian Rhapsody has a second harmonic component of the British power line frequency in it at about -60db near the beginning of the song! 

     Once some of the code that does THAT sort of analysis is properly integrated into the Propeller Debug Terminal, then it will be possible to use the P2 as a real-time audio analyzer, on the one hand, and as whatever else on the other - with an eye toward not just making another oscilloscope (64 channels at 200Mhz for digital signals in logic mode anyone?), but as an eventual platform for a Euro-Rack compatible PC or not-PC based modular synthesizer. 

     This is of course once again why it would be so nice to have C++, or Object Pascal on the P2 - for "self-hosting" purposes, which is certainly doable, but implementing a GUI in assembly language is not my cup of tea.  Much better therefore to simply write a compiler that will be able to generate code that has all of the required features.  As mentioned earlier - UCSD Pascal is mostly done, so that when I finish the body part I can look into either implementing a p-machine on the P2, now that I have most of what I need to do floating point, sets, and the various other intrinsic functions (such as mass storage, WRITELN, etc.)  that aren't a part of the UCSD distribution, and which need to be written or compiled to native form; whether I end up going the p-code route or entirely native or not.

     There is something very interesting that has come out of my digression into porting UCSD pascal, however, and that is something that is going to turn out to be very useful in the long run, no matter what high-level language I eventually use for building more aggressive applications that run directly on the P2 - and that is something that I discovered while porting the WRITELN function, so as to be able to run more of the Pascal compiler code relatively "unmodified",  by doing mostly simple find and replace conversion of Pascal keywords to C. 

     Where that will turn out to be useful will be because although the C language "var_args" function does not pass type information; I was able to implement a proxy class that automatically constructs a "debug_param" object, where I eventually renamed the object's class: "s_param" in order to have a hint of LISP like s-expressions in the type name.  Thus, the s_param objects capture type information, allowing WRITELN to in effect be used not just for printing, but for PARSING - for example, streams of English commands like MOVETO, LINETO, or ELLIPSE, such as the commands are spelled out in the Parallax Debug protocol, (or in OpenGL!) so that instead of trying to link the now converted Delphi code against some obscure '386 assembly, rather - why not use a TREESEARCH variant to identify tokens in the debug stream? 

     Even though I had to implement this myself. since it wasn't in the Pascal distro, it is clear now how the method can be extended (by which WRITELN was implemented) so as to specify which device is to be written to, i.e., by assigning each terminal window its own unique ID, which can be separate from its Microsoft based Window Handle or Window pointer. This would turn the old-fashioned lowly Pascal WRITLEN command into a powerful asynchronous IO pipeline redirector with a built-in command...

    Read more »

  • Always Play Bach

    glgorman10/26/2021 at 05:32 0 comments

     If you have never seen the videos on YouTube about "Pachelbel Rant" and how almost every pop song ever written just might be based on "Pachelbel's Cannon in D" - please search for it and check it out NOW, and while you are at it - check out another group that claims that if you can "learn to play just four chords" you can crank out every pop hit from the last 40 years and that one is by a group that calls themselves "Axis of Awesome" and you can find their variations of the "Axis of Awesome Four Chord Song" also on YouTube.

     I have my own theory of course, that nearly every rock song ever written can be improvised from J.S. Bach's "Fugue in G"., which is a truly wonderful piece, and eventually, I will be uploading "something" or another to YouTube demonstrating some live "audio in and sheet music out" capabilities either running entirely on the parallax propeller P2 chip, including VGA/HDMI generated on-chip; or else (and initially) by just using the propeller in oscilloscope mode, while running the spectrum analyzer software on a PC connected via USB., but of course, I had to throw together "some kind of sheet music software" that doesn't need 250 Megabytes.  Right now this one is using 177 LINES of C++, and even though we don't have C++ yet on the Propeller P2, as long as I avoid polymorphism, multiple inheritances, C++ exceptions, etc., and try to stick to things that work well with structs, namespaces, and MoveTo and LineTo style drawing - this is very doable. 

     Also, I am adding rudimentary support for actually PRINTING sheet music to the C++ version of Propeller Debug Terminal and will be adding some source code to the repository in GitHub very shortly.  In the meantime, you might want to check out the "music_notation_test.pdf" upload that I am putting in with the files on this site, i.e...., as a part of the proof of concept.  Object Pascal for the Propeller would also be a good way to pull all of this together; whether based on UCSD Pascal, or whether based on Lazarus, either would serve as a very nice way to get a  GUI up and running with some real workhorse software - so that is how all of this is going to come together. 

    In any case, perhaps this would be a good time to dig into some of the internals of how the data stream decoding/parsing and command processing is going to work, in the various modes that are going to be offered on the PC side of things.  Here is a debugging session where we can see how a message from the serial/USB communications object is being generated into the application's "mainFrame" which in turn is in the process of being tokenized. 

    This particular function takes strings of characters as they are received and then splits them whenever a line break occurs.  If you look carefully, the data stream from the Propeller has a few places where there are some embedded commands like "SCOPE s POS 710 1000 size", followed on the next line (aaargh!) by the parameters "512 276 samples 512 rates 512 longs_8bit ".  This is of course what needs to be further parsed out, that is to say, by further tokenizing each string, in order to recognize keywords like "SOCPE" or "ELLIPSE", on the one hand; which I why I have had to implement my own TREESEARCH and symbol table management functions.  So that means now that it is a simple matter to fully tokenize each string, and then either allow the original code to process the data by feeding it whatever it needs each time that it makes a call to "NextElement(ele_num)", so that this thing will finally work just like the original Delphi.  Pretty simple actually.  Still what I want to do, as I have mentioned before, for example, while looking at how the UCSD Pascal compiler works - is to try to express the grammar of the debugging protocol, not with long chains of case statements, which go on for 100's, but not quite 1000's of lines, but rather I want to be able to express...

    Read more »

  • 99 Bottles of Recursive Pascal Beer on Humpty Dumpty's Wall

    glgorman10/21/2021 at 11:23 0 comments

    As you probably know time travel is probably impossible, at least for practical purposes, no matter what Calvin Klein says.  Neither are you likely to be unbreaking an egg anytime soon, no matter how hard all of the king's horses and all of the king's men may hope for.  On the other hand, as far as tricking a C++ compiler into chowing down on Pascal programs with "only" minimal modification; well that one might not nearly be as difficult as inventing time travel or warp drive might actually turn out to be in practice.  Now one of the problems with getting a C++ compiler to chow down on Pascal source is the fact that Pascal allows for so-called "nested procedures or functions" which means that PROCEDURE A can have PROCEDURES B and C declared inside A, and also maybe PROCEDURES D and E declared inside A in such a way that A can call B which calls C, which then calls B over and over again recursively, which might be used create a "wall object" and 99 "beer" objects using recursion on the stack (if so desired) through recursion, and then have B or C call A again in a re-entrant fashion so that A can now call procedures D and E, when then operate recursively to pull down some of the bottles and pass them around., at least until an "out of beer exception occurs."  Not that you can't do that in C++, but can it be done with DEEPLY nested and mutually recursive functions - and in such a way that when you look at the source code it looks like a Pascal program has been converted to use nested namespaces - which is allowed - just not nested functions.  Now let's make it even harder, AND not add any new passed parameters to the original functions, since one of the nice features about Pascal nested procedures, is that the inner nested procedures have access to the outer procedure's local variables, that is to say without having to de-reference any passed pointers, and then otherwise use a WITH statement, (which would be "evil", and which also doesn't exist in C++.

    Now to throw another log on the fire, although a template based on 99 bottles of recursive Pascal beer might be useful for implementing fun things like editors with 99 levels of undoing, or Tiny-OS kernels that support up to 99 or more concurrent processes; there are actually even bigger fish to fry.

    Even bigger fish to fry?  How about the fact that Pascal allows for some very nasty, even though it is not quite Halloween yet, Here is some code that looks like it just might have come straight out of some "sequel that never got made to the Rocky Horror Picture Show" like data structures.  Like this one from the Pascal source of UCSD Pascal: (So yeah, "Let's do the time warp again!")

    IDENTIFIER = RECORD
        NAME: ALPHA; LLINK, RLINK: CTP;
            IDTYPE: STP; NEXT: CTP;
                CASE KLASS: IDCLASS OF
                    KONST: (VALUES: VALU);
                    FORMALVARS,
                    ACTUALVARS: (VLEV: LEVRANGE;
                    VADDR: ADDRRANGE;
                    CASE BOOLEAN OF
                        TRUE: (PUBLIC: BOOLEAN));
                          FIELD: (FLDADDR: ADDRRANGE;
                            CASE FISPACKD: BOOLEAN OF
                        ...
    Read more »

  • Where this train is really going?

    glgorman10/20/2021 at 11:49 0 comments

    Pascal running on real Apple II hardware.  No big deal.  In my all too ample spare time I suppose that I could actually get the PS/2 keyboard to Apple IIe interface working, or I could just simply buy one already made, I think that there are some other people who might still be making them and selling them.  Otherwise, a big mess of wires is kind of hard to manage, but not impossible. 

    But would be a lot more fun to just simply bite the bullet and try to find a replacement keyboard case for the IIe, and go pure retro - with a genuine Apple II compatible SCSI  drive in a beige case + the scarce as hen's teeth Dou Disk floppies?  Now as it turns out - I would actually like to be able to access my Pascal stuff from my college days, but it's not a high priority.  Now, remember - jealousy is a green monster - but maybe it could be beige, under the right circumstances. 

    Of course, if I were to yank the ROMs from the SCSI card - even though the code type is 6502; it might serve as a basis for a very lightweight SCSI driver for Arduino, or Propeller. Not that Linux doesn't have some nice open-source codes that can simply be downloaded and read - but as always - that stuff is too bloated to run on an Arduino or a Propeller.

  • Pocket Full of Zero Days?

    glgorman10/20/2021 at 11:32 0 comments

    "One of these days everyone is going to know that Clint Eastwood is the biggest Yellow Belly in the West!"  Right?  So even though "I have a bad feeling about this!", it isn't all that bad, unless it is actually worse.  Earlier, while working on the port of UCSD Pascal for the Parallax P2 and other platforms, I came across this mess, in the original Pascal - which I mentioned actually hints at a zero-day issue for many a system.  Which of course presents an ethical conundrum, even if this is HACKADAAY, i.e., in terms of "ethical disclosure."  Well, in any case here is the offending code:

    BEGIN (* INSYMBOL *)
       IF GETSTMTLEV THEN
        BEGIN
           BEGSTMTLEV := STMTLEV;
           GETSTMTLEV := FALSE END;
           OP := NOOP;
     1:    SY := OTHERSY;
    (* IF NO CASES EXERCISED BLOW UP *)
       CASE SYMBUFP^[SYMCURSOR] OF
       '''':STRING;
       '0','1','2','3','4','5','6','7','8','9':
            NUMBER;
       'A','B','C','D','E','F','G','H','I','J','K','L','M',
       'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
       'a','b','c','d','e','f','g','h','i','j','k','l','m',
       'n','o','p','q','r','s','t','u','v','w','x','y','z':
            IDSEARCH(SYMCURSOR,SYMBUFP^); (* MAGIC PROC *)
    ETC ...

     Now apart from inefficiency, what harm could there be in an otherwise "harmless little case statement" (insert Monty PYTHON quote here) which has a separate case for every letter of the alphabet, so that it probably compiles to an if then else chain with at least that many branches?  Answer:  Besides being inefficient in and of itself, on a modern system, this coding style causes the cache lines to flush every single time, so that code that could have been run out of L1 cache might get run out of L2, or maybe L3 if you are lucky, or maybe on some memory starved systems it will trigger a page fault every single time. 

    Then besides 'nerfing the cache lines;  chances are each time through the chain the branch will be taken or not taken at a different point so that the branch predictor on any modern CPU (that has one) will get it wrong - every single time, contributing to further inefficiencies, and therefore so also setting the stage for new, not yet fully imagined MELTDOWN or SPECTRE type attacks; where even if a remote attacker can't steal passwords by analyzing the time to respond to millions of DNS requests over a network - just by listening in to other traffic, i.e., that is by devising a passive packet sniffing strategy that works by putting the "man" in the middle in the form of an otherwise seemingly well-behaved router.  

    How knows?  Maybe they can.  Regardless, this still sets the stage for other shady dealings like carefully crafting and DDOS (denial of service), whereby the rogue actor - "the unicorn" is  "in the garden" so to speak, even if the DDOS actually gets routed through Torrents, to that it appears to be inseparably co-mingled with legitimate traffic, and that is how someone could, in principle - do a carefully planned DDOS against certain BGP infrastructure - and take down DNS.

    Now if just like "Wall Street", the "circuit breakers trip", and the LRU caches flush - well, that is one variation, and thus the "reindeer games" continue.

    Now I wasn't going to say anything about this - but - well, maybe I changed my mind after another bad patch Tuesday because of the "big company"  with "the small name", on the one hand, and not just because some people still can't FACE the music on the other hand.  But now, you know who in the aforementioned has 'nerfed the whole AMD Ryzen line, with some kind of "oops", exposing yet another critical flaw.

    Whatever happened to coding standards?  Or testing?  

    P.S. For a good time (or not-so-good time) Google the phrase for a paper published by the Linux Foundation entitled "Vulnerabilities in the Core" if you haven't heard about it already. ...

    Read more »

  • Microsoft does it again!

    glgorman10/18/2021 at 21:07 0 comments

    How many times is this going to happen?  Sometimes I lose a whole day or more having to reinstall everything, that is to say when they not only manage to nerf the updates, but they implode the system restore points.  Hopefully, they didn't do to much damage this time.  Otherwise, UCSD Pascal is getting closer to actually being able to compile programs for the Propeller or maybe for one of those 100Mhz 6502 things, or whatever - so that while a NOR computer would certainly be interesting, an FPGA-based something or another would be more likely.

    As expected, the fact that the UCSD compiler has some deeply nested procedures, which because of the nature of the language might also be recursive, does present an interesting challenge - since C/C++ does not allow "local functions" that it otherwise considers illegal.  So an interesting question therefore is whether it is even possible to convert some Pascal programs without extensive re-architecting of the overall design of an application, such as by requiring the use of lambdas, or tables of function pointers, (which I like - but not if we don't have that level of sugar coating available for use with microcontrollers - yet) - or adding a passed parameter for frame tracking to each and every function - which is a pain in the ass - as when let's say - procedure A calls nested procedures B and C recursively, as if to implement 99 bottles of beer on the wall on the stack, and then when an "out of beer" exception should occur, either the "pull one down" or "pass it around" functions have to call some other functions, let's  call them D and E and F, where E and F are inside of D, which is also inside of A, and then a callback to A might result in - well you get the idea, a fresh call to B or D - and then the compiler has to somehow generate code that preserves the invocation record for the entire call history, so that just in case the latest E wants to access a variable from the most recent B or C, is that even possible?  What a mess!

    So when I ask is it possible, I mean is it possible to go into a Pascal program and simply use find and replace to replace all of the BEGINs and ENDs with curly braces, and otherwise simply pour a little sugar on where it is needed to deal with WITH statements and the rest - but otherwise leave the body of the Pascal procedures exactly as written,  that is to say so that most of the re-write can be done with find and replace in a word processor?

    Interestingly enough - it appears that the answer is YES - and that something like this does the trick!

    class DECLARATIONPART::USESDECLARATION:
        public DECLARATIONPART
    {
    protected:
        struct SEGDICT
        {
            DCREC    DANDC[MAXSEG];
            ALPHA    SEGNAME[MAXSEG];
            int      SEGKIND[MAXSEG];
            int      TEXTADDR[MAXSEG];
            int      FILLER[128];
        };
        bool         FOUND;
        int          BEGADDR;
        CTP          LCP;
        LEXSTKREC    LLEXSTK;
        ALPHA        LNAME;
        SYMBOL       LSY;
        OPERATOR     LOP;
        ALPHA        LID;
    
    protected:
        USESDECLARATION(bool MAGIC);
        void GETTEXT(bool &FOUND);
    };
    

    So in the original Pascal source "USESDECLARATION" is a procedure that takes exactly one BOOLEAN parameter called "MAGIC", and then "USESDECLARATION" needs to be able to call a nested function called "GETTEXT" which in turn needs to be able to access some of the local variables that were previously declared in the...

    Read more »

  • Notes on creating an FPU for the NOR computer.

    glgorman10/16/2021 at 05:16 0 comments

    Earlier I mentioned throwing some code together where I began implementing a complete ALU for a hypothetical computer that uses only NOR gates, figuring that by working in C/C++ with an eye toward being able to port "whatever seems to work" to system C or even Verilog, then, well, why not?  Then I realized of course that since I eventually want to run UCSD Pascal, or perhaps Modula II, or even ADA on the Parallax Propeller 2 - then with a few other code tricks up my sleeve, this could become the basis for turning my Frame Lisp project into a full-fledged compiler.  So why not implement floating point, especially if I am going to eventually need it - for whatever this transmogrifies into?

     So this is how 32-bit floating point multiplication works, and what IEEE-754 style looks like, even if it isn't fully tested for STRICT compliance with the standard or any standard - but it does seem to work, which is enough for now:

    real real::operator * (real arg)
    {
        short _sign;
        real result;
        short exp1 = this->exp()+arg.exp()-127;
        unsigned int frac1, frac2, frac3, frac4, fracr;
        unsigned short s1, s2;
        unsigned char c1, c2;
        _sign = this->s^arg.s;
        frac1 = this->f;
        frac2 = arg.f;
        s1 = (frac1>>7);
        s2 = (frac2>>7);
        c1 = (frac1&0x7f);
        c2 = (frac2&0x7f);
        frac3 = (c1*s2+c2*s1)>>16;
        frac4 = (s1*s2)>>9;
        fracr = frac1+frac2+frac3+frac4;
        if (fracr>0x007FFFFF)
        {
            fracr = ((fracr+(1<<23))>>1);
            exp1++;
        }
        result.dw = (fracr&0x007FFFFF)|(exp1<<23)|(_sign<<31);
        return result;
    }
    

     Oh, what fun!  Haven't tried compiling it yet on either the Propeller or for Arduino, but I do know that some versions of the Atmel architecture such as the Mega 2560 series have hardware multiplication at least as far as being able to 8-bit by 8-bit on the chip, so this could get interesting performance wise, let's say when the time comes so as to be able to compare the performance of a 6502 emulator running UCSD p-system Pascal, which itself runs as an emulated 16-bit p-machine running on the 6502 whether real or virtual, vs. whatever the performance might be for floating point if the p-machine were running under direct emulation.  I will be putting some code for this up on this site, as well as (eventually) on Git, for anyone who wants to tinker with a greatly simplified calculator example, which is now in the process of getting floating point!! 

  • Shall we play a game?

    glgorman10/10/2021 at 21:13 0 comments

    I know what you are thinking.  As WOPR (pronounced "whopper") said when asked "Is this real or is this a simulation"?"  -- What's the difference?  Right?  What are a few megatons among friends, or former friends?  On the other hand, if you have ever run spectrum analyzer software on a song like "Bohemian Rhapsody" let's say, you might have noticed a very prominent second harmonic component of the British power line frequency sticking out prominently at around -60db, that is to say at 100Hz.  Wow!! Let's have a look at a screenshot of a processed sample block from the CD:

     Here is what is happening.  The yellow vertical lines in the middle window are the upper and lower bounds of the range of notes available on a standard full-size piano, and the minor divisions on the horizontal axis represent semi-tones, i.e.. so that there are 12 divisions per octave based upon a so-called log-log plot of the spectrum.  Thus for this image, I am performing an initial 1024-point FFT, whereby I take the output of that first FFT and break up the spectrum into eight blocks of frequencies, as indicated by the dialog box, just like MP3 on the one hand, that uses a "filter bank" to split the spectrum up into 32 sub-bands, which can then be subjected to further processing - such as in separate threads, or according to different algorithms, according to the need for beat and bass line detection, harmonic analysis, etc.

     Hence, one of the things that I have found a need for is the creation of a menu that allows me to select different FFT parameterizations, so that I try every possible combination, including ridiculous ones like million-point FFTs that split the spectrum into individual channels which are, whatever - lest say 10Hz wide, if we wanted.  Thus what the upper window represents, is in the present case, taking like I said: an initial 1024 point FFT, which is then split up into 8 blocks of frequencies, and then converted back into TIME-DOMAIN signals, resulting in what you see on the top window.  Thus that window is running an eight-channel, (actually 16 because of stereo pairs) oscilloscope, that is displaying the output of the aforementioned "poly-phase filter tree", although such an oscilloscope could just as well be used as a "simple" logic analyzer, in the old-fashioned sense.

    Now all of this has interesting implications, For example - by taking an audio signal and splitting it into something like 128 (or 256) time domain signals, an initial 44100-hertz sample rate (stereo signal) can be turned into 128-time domain signals where the sample rate for the sub-bands, (works as if we have made a kind of loud-speaker crossover from hell), is 345 Hz since 44100 divided by 128 is 344.53, and this goes a long way toward solving the event detection problem, if one of the things that we want to to is generate MIDI on and MIDI off events on a note by note bases, either as part of an audio in and sheet music out kind of system, or audio in and then possibly drive a piano with light-up keys, (if you have one or want to build one).  or else if you wanted an application with light-up keys, and a piano on the screen - maybe that would be an ideal project for Android or as a WebGL-based application for general use.  But first, we need to create the right metadata so that we can stream it, if at the end that is what we are most likely to want to do.

     Then there is the issue of speech recognition.  Now I know that there are several "bots" on this forum that use Google speech, or Apple speech, and yet you still can't say "OK Google - take dictation", and why not?  Besides that, do you really want to let Google listen to everything you say and do, with no accountability, that is to say - NO why what so ever so as to be able to "look under the hood" and ask "just how much data is being processed locally on the device"  before a query goes out the to cloud. ...

    Read more »

  • How this all adds up.

    glgorman10/08/2021 at 11:37 0 comments

    O.K., that's not what this log entry is about either; but it does seem relevant.  Would you prefer "Where this train is really headed?  And is the light at the end of the tunnel another oncoming train?"  I do try however to begin every log entry with a catchy title.  In any case, I threw together a quick example in C++ of how to implement a function table, which is also better described as a "table of function pointers" which can be used, as in the example I am about to discuss as a part of a simple programmable calculator application, or the techniques can be applied in such a way as to make for a very elegant emulator for any CPU platform, or else this is how we finally will be routing commands from the debug stream to the appropriate oscilloscope, debugging, or interactive windows in the Propeller Debug Terminal, and it is also a very useful technique for compiler writing, as we will see later on. 

    #define PI (3.14159265358979323)
    typedef enum { add=0, sub=1, mult=2, divi=3, }  opcode;
    typedef double (*ftable[])(const double&, const double&);
    
    class calculator
    {
    protected:
        double reg[16];
        static double (*ftab[4])(const double&, const double&);
        static double fadd(const double &, const double &);
        static double fsub(const double &, const double &);
        static double fmult(const double &, const double &);
        static double fdiv(const double &, const double &);
    
    public:
        static double exec(opcode, const double &arg1, const double &arag2);
        static int main();
    };
    

     It looks simple enough, with lots of static member functions that do all of the heavy lifting for us, along with a "set of registers" that some other functions, which are not provided in this example might use to implement a complete calculator.  Now let's look at the functions, that we do have:

    #include "stdafx.h"
    #include "calculator_test.h"
    
    ftable calculator::ftab =
    {
      &calculator::fadd,
      &calculator::fsub,
      &calculator::fmult,
      &calculator::fdiv,
    };
    
    double calculator::fadd(const double &arg1, const double &arg2)
    {
        double result;
        result = arg1+arg2;
        return result;
    }
    
    double calculator::fsub(const double &arg1, const double &arg2)
    {
        double result;
        result = arg1-arg2;
        return result;
    }
    
    double calculator::fmult(const double &arg1, const double &arg2)
    {
         double result;
        result = arg1*arg2;
        return result;
    }
    
    double calculator::fdiv(const double &arg1, const double &arg2)
    {
        double result;
        result = arg1/arg2;
        return result;
    }
    
    double calculator::exec(opcode op, const double &arg1, const double &arg2)
    { 
        double result;
        result = (ftab[op])(arg1,arg2);
        return result;
    }
    
    int calculator::main()
    {
      double val1, val2;
      val1 = exec(mult,2,PI);
      val2 = exec(mult,exec(add,3,4),exec(add,4,6));
      return 0;
    }

    Now if you have never seen anything like this before, what typedef enum { add=0, sub=1, mult=2, divi=3, }  opcode and typedef double (*ftable[])(const double&, const double&) do is exactly as described, they create a new type of variable that we will call an "opcode", and then another type of variable that we are going to use later to map opcodes onto specific functions, and thus what the "executive" does is to (when presented with an opcode and appropriate parameters) -- look up the function that is responsible for carrying out the operation described by that particular opcode or instruction.  With no need for 256 if-then-else statements, the equivalent case statements in Pascal or switch statements in C/C++.

    And thus:

    ftable calculator::ftab =
    {
      &calculator::fadd,
      &calculator::fsub,
      &calculator::fmult,
      &calculator::fdiv,
    };

    --- actually creates the function table, and this is how we call the desired function with one line of code, instead of sometimes thousands.  Seriously.

    result = (ftab[op])(arg1,arg2);

     Now, this is where things get surreal.  I have so far converted about 2500 lines of the UCSD Pascal p-system compiler from Pascal to C++, trying to be as strict as possible...

    Read more »

  • Whether or not, to say "whether or not" or not.

    glgorman10/07/2021 at 23:53 0 comments

    Or is it this or that, or neither this nor that?  Perhaps it doesn't matter.  That's not what this post is about, unless maybe it is.  Writing a compiler from scratch is no small task, on the one hand, but then again, on the hardware side of things there are always going to be those people who want to do things like "build" a compete CPU or at least an ALU with nothing but NOR gates; just like the Apollo guidance computer.  So while building such at beat is not in the cards, simulating on with software is certainly fair game, especially if there is also the possibility that a compiler for such a beast might emerge in the very near future.  So lets have a look at some code.

    inline DWORD nor(DWORD r1, DWORD r2)
    {
        DWORD result;
        result = ~(r1|r2);
        return result;
    }
    
    inline DWORD not(DWORD r1)
    {
        DWORD result;
        result = nor(r1,r1);
        return result;
    }
    
    inline DWORD or(DWORD r1, DWORD r2)
    {
        DWORD result;
        result = not(nor(r1,r2));
        return result;
    }
    
    inline DWORD and(DWORD r1, DWORD r2)
    {
        DWORD result;
        result = nor(not(r1),not(r2));
        return result;
    }

    So far so good.  Just wait until you try to debug addition.  But first, take a look at how we do "and" via DeMorgan's law.  Fairly straightforward.  Now assuming that you have addition, and if you also have the square of the first 255 integers in a look-up table, 8-bit by 8-bit multiplication follows, like so:

    inline unsigned short mult8 (unsigned char c1, unsigned char c2)
    {
        unsigned short s0, s1, s2, s3, s4;
        if ((c1==0)|(c2==0))
            return 0;
        if (c1==1)
            return c2;
        if (c2==1)
            return c1;
        s0 = (unsigned short) add(c1,c2);
        s1 = (unsigned short) sub(c1,c2);
        bool m_odd = (s0&0x1?true:false);
        bool m_neg = (s1&0x8000?true:false); 
        if (m_odd) {
            s0 = (unsigned short) add(s0,1);
            s1 = (unsigned short) add(s1,1);
        }
        s2 = (unsigned short)(m_neg?add(not(s1),1):s1);
        s0>>=1;
        s2>>=1;
        s3 = (unsigned short) sub(lut1[s0],lut1[s2]);
        if (m_odd)
            s4 = (unsigned short) sub(s3,c2);
        else
            s4 = s3;
            
        ASSERT(s4==c1*c2);
        return s4;
    }

    Yes, script kiddies and sugar friends, that does the trick.  Which kind of makes me wonder what it would look like if I had a good C++ 6502 compiler, or C++ for the NOR machine, that is.  Care to try for 16 bits?  I think that this works, but I haven't run every possible test:

    inline DWORD square(unsigned short r1)
    {
        DWORD t0,result;
        DWORD t1, t2, t3;
        unsigned char highbyte, lowbyte;
        lowbyte = r1&0xff;
        highbyte = (r1&0xff00)>>BYTESIZE;
        t0 = (lut1[highbyte]<<WORDSIZE)|(lut1[lowbyte]);
        t1 = mult8(highbyte,lowbyte);
        t2 = t1<<(BYTESIZE+1);    
        t3 = add(t0,t2);
        result = t3;
        ASSERT(r1*r1==result);
        return result;
    }
    
    inline DWORD mult16(unsigned short r1, unsigned short r2)
    {
        DWORD result;
        DWORD t1, t2, t3, t4;
        t1 = add((DWORD)r1,(DWORD)r2);
        t2 = sub((DWORD)r1,(DWORD)r2);
        t3 = square(t1);
        t4 = square(t2);
        result = sub(t3,t4)>>2;
        return result;
    }

    Now, this is starting to look like it would be a good way to use overloaded operators in templates, that is to say, if a full-featured C++ compiler were available.  Conformant IEE-754?  Not quite there yet.   Even though I am not currently doing anything with this code, it is interesting from the point of view of compiler writing; that is to say - to the extent that it should be possible to write a complete compiler for any language that might use only a very limited instruction set, such as NOR, SHIFT, COMPARE, and JUMP, along with perhaps CALL, LOAD, PUSH and POP.  That means of course that when writing a compiler for a new platform, it might be useful to initially make use of only a subset of instructions, i.e., with respect to what is actually available with a new architecture.  Then, for example, one approach might be to use C++ classes which provide the facility for the use of virtual functions.  Thus, one might declare a "fake.cpu" which defines virtual functions for all of the primitives and then use a...

    Read more »

View all 12 project logs

  • 1
    Getting Started.

    First and ideally you will want to obtain ANY product that has the Parallax P2 processor.   Then you can use some of the available third party tools such as TAQOS Forth, or Flex C, or Spin to develop an application for your P2.  It can be a simple application, such as a number base conversion program or a tic-tac toe game that is purely text based.   Start with something that is simple and familiar, and then ask yourself - now what do I really want to do with this?  Besides playing tic-tac-toe via a serial port interface, you might want to monitor the local weather reports, and then use Bluetooth instead to remotely control a lawn sprinkler controller, or you might want to monitor your mailbox to see if the mail has arrived.  What you do with all of the I/O that is available is up to you; but a big hurdle remains - that is to say even if you build the best lawn sprinkler controller on the planet - and that is WHY ARE YOU still running your bespoke applications in the manufacturers sandbox?  Got audio in and MIDI out running yet - great!  Whether you do, on not - now you are ready to proceed to step two.

  • 2
    Getting out of the Sandbox.

    Now the fun begins.  Sometimes also referred to as "removing the training wheels from your bicycle."  If you follow the links to GitHub you will find a project entitled Propeller Debug terminal.  If you have Visual 2005 or later, you should be able to import the source files that are contained therein, and use those files to build a project that is functionally similar to a product called PNut; which is an official Parallax product that has been around for many years.  Unfortunately neither PNut, or the Parallax Terminal, provides any capabilities for arbitrary customization.  The situation with Arduino, I have found to be even worse, such as with certain Java based tools that cause the serial port to hang, and thus requiring PC users to reboot (the PC!) every time there is a glitch when the serial port suffers the dreaded "port in use by another application error".  This is a long-standing issue with THAT platform.

     On the Propeller side, however; Chip Gracey at Parallax published the original Delphi source code for PNut in mid-summer 2020, so that I was able to create a mostly complete C++ version, which adds some rudimentary UNICODE/IME support, TCP/IP access, more reliable high speed serial interfacing, multiple documents and views. etc. 

    Now if you have a so called "bespoke application", let's just make something up - maybe you have a weather application that checks the weather reports, but you need Bluetooth interfacing for your lawn-sprinkler controller.  Then what you are going to want is the files "prop_serial.cpp", "com_object.cpp", and so on, and maybe "telnet.cpp" from the Frame Lisp repository if you want a TCP interface on the PC side.  In that case you would simply integrate the aforementioned files into YOUR custom application and now you can "rock and roll with the big cats!"

    Oh did I mention rock and roll?   

  • 3
    It's time to Rock and Roll!

    Did I mention rock and roll?  Did I just repeat myself?  Music is like that.  If you have a Euro-Rack based system, and have looked at my previous project "Computer Motivator", you might have noticed by now that there is a suspicious dimensional similarity if you compare the size of a typical four-inch in-wall blue electrical box that you can buy at Home Depot for a few dollars, and the apparent size of a Euro-Rack module, even if it might need to be a "double-wide".  This is the essence of a great hack.  Spend NOTHING that you don't have to!  Use whatever is already on hand.  For now this will be our project case.  It requires some minor modification using a drill to accommodate the USB cable, and if we were to mill and drill out a nice bezel, and add some jacks, and some knobs, etc., then we really would be ready to rock and roll! 

View all 4 instructions

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates