/* Copyright (C) 2015-2018 Gustavo Conte URL: https://gu.pro.br This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id$ */ #include "MIDI.h" #include #include #include #define ROOT 57 // this is kinda the middle of our keyboard #define MODULLA 5 // value of Fib(n)%MODULUS // this is the essence of interval // generation int main(int argc,char* argv[]) { ///// Amalgamation vars int note=0, noty=1; // note interval increment, max N of notes on realejo[] int counter=0; // Amalgamation counter to trigger repopulation of realejo[] int g=0, x=0, y=1, z=0, w=0, j=0, i=0, k=0, f=0; // indexes indexes and counters too int flowZ = 3; // flowZ define max multiplier for note pro longation double mojo = 1; // slightly vary rhythm/speed // ( 1x argv[3] or 2x argv[3] ) in millisecs double arpflow = 0, longflow = 0; // this keep sync of child tracks // and primary tracks respectively double a = fabs(atof(argv[3])); // third parameter -> durations y *= atof(argv[3])/fabs(atof(argv[3])); // increment/decrement flow direction // of all note interval operations; // determined by argv[3] signal (+/-) on cmdline // realejo matrix is where the generated phrases of notes are stored int *realejo, MODULUS=MODULLA; // MODULUS is the essence of the algorithm // we will apply % operation to each Fib(n) // to generate each interval for each new note; if ( argc > 5 && atoi(argv[5]) != 0 ) // fifth cmdline param enables all tracks // also changes MODULUS, which is the essence of the algorithm MODULUS = abs(atoi(argv[5])); /// argv[4] determines, from cmdline, // the max size realejo[] matrix can become in each repopulatio int AMALGAMATION=1; // as u can see, min size for realejo is two notes; if ( atoi(argv[4]) ) // zero max size note allowed, duh AMALGAMATION += abs(atoi(argv[4]))+1; int ROOTZ = ROOT+(y*3); printf("root note-%d > max phrase is: %d ", ROOTZ, AMALGAMATION); //////////////// libGMP vars // to hold our real huge integers mpz_t AMALGAMA; // the max realejo[] matrix size to hold notes per phrase mpz_t n, itt, max_itt, prev, next, mody, Z, nully, moda, modY, modYY, modYYY; // init Fibonacci vars mpz_init(n); mpz_init(itt); mpz_init(max_itt); // Fib n, Fib final mpz_init(prev); mpz_init(next); // Fib n-1, Fib n+1 // init Amalgamation vars mpz_init(AMALGAMA); mpz_init(mody); mpz_init(Z); mpz_init(nully); mpz_init(moda); mpz_init(modY); mpz_init(modYY); mpz_init(modYYY); /////////////////////////////////////////////////// initialize libmidi stuff. char stringy[1000]; // just to generate midi filename // generate MIDI filename - "Fib(i)-Fib(f)_(signal)DURATION.mid" // sprintf(stringy, "%d-%d_%f.mid", atoi(argv[1]),atoi(argv[2]),atof(argv[3])); MIDI::File file(stringy); MIDI::Header* header=file.header(); header->setNumTracks(9); header->setTicksPerBeat(120); //////////////////////////////// create all three types of tracks ///////////////////////////////// and their 'mirrors' with transposed notes ////// FOR EACH type of track, we got std track + higher pitch + lower pitch MIDI::Track* track[3]; // PRIMARY MIDI::Track* _track[3]; // 2nd MIDI::Track* __track[3]; // 3rd ///// construct/init all; for (z=0; z<=2; z++ ) { track[z]=new MIDI::Track(); // primary track _track[z]=new MIDI::Track(); // secondary track __track[z]=new MIDI::Track(); // 3rd track } //////////////////////// we also got a foobar experimental 4th track !!!!! MIDI::Track* ___track=new MIDI::Track(); /// still dunno what this fourth track should do //////////////////////// we also got an awesome beat track to aid post-production on trackerZ! MIDI::Track* beatT=new MIDI::Track(); /// you can use Renoise break samples // so each note on this track can play a pattern made in the tracker MIDI::MetaGenericEvent* timeSignature=new MIDI::MetaGenericEvent(0,MIDI_METAEVENT_TIMESIGNATURE,4); timeSignature->setParam(0,4); timeSignature->setParam(1,2); timeSignature->setParam(2,24); timeSignature->setParam(3,8); MIDI::MetaGenericEvent* keySignature=new MIDI::MetaGenericEvent(0,MIDI_METAEVENT_KEYSIGNATURE,2); keySignature->setParam(0,0); keySignature->setParam(1,0); MIDI::MetaNumberEvent* tempo=new MIDI::MetaNumberEvent(0,MIDI_METAEVENT_SETTEMPO,3,900000); ////////////////////////// set params of all tracks for (z=0; z<=2; z++ ) { track[z]->addEvent(timeSignature); track[z]->addEvent(keySignature); track[z]->addEvent(tempo); _track[z]->addEvent(timeSignature); _track[z]->addEvent(keySignature); _track[z]->addEvent(tempo); __track[z]->addEvent(timeSignature); __track[z]->addEvent(keySignature); __track[z]->addEvent(tempo); } // MAXIMUM REALEJO SIZE SET HERE - - - now alloc matriX !¡ realejo = (int *) malloc(AMALGAMATION*sizeof(int)); for (z=0; z%Zd\r", n); mpz_add(itt, next, prev); mpz_set(prev, next); mpz_set(next, itt); } mpz_set_str(max_itt, argv[2], 10); printf("Calculado Fib(%d)!\n ", atoi(argv[1])); //////////// with initial Fib(n) calculates, proceed to // populate realejo[] // mpz_set(Z, n); mpz_nextprime(Z, Z); mpz_mod_ui(mody, Z, AMALGAMATION); noty=mpz_get_ui(mody); if ( noty%2 ) noty++; for (z=0;z note durations /* AMALGAMATION */ // [http://www.krizka.net/projects/libmidi/] // // ///// Let's PLAY! mpz_set(Z,n); // reinitialize seed longflow = 0; // reinitilize sync counter if ( g ) // we skip first phrase, usually sux for (z=floor(((y*(noty-1))+(noty-1))/2); z < noty && z >= 0 ; z+=y*(1+(int)ceil(sqrt(sqrt(noty)))) ) { //for (z=0; z < noty ; z++ { //play phrase // First, determine primary amount of simultaneous notes; mpz_nextprime (Z, Z); // start from a prime number mpz_add(Z, Z, n); // then try force a composite number mpz_mod_ui(modY, Z, 3); // so modulus may result zero; //// 2nd track amount of notes mpz_nextprime (Z, Z); mpz_add(Z, Z, n); // again, try force a composite number mpz_mod_ui(modYY, Z, 3); // so result may be zero too // 3rd track amount of notes played together mpz_nextprime (Z, Z); // keep Z a prime number mpz_add(Z, Z, n); // again, try force a composite number mpz_mod_ui(modYYY, Z, 3); // so result cannot be zero now f=1; mpz_nextprime(Z, Z); // so next result is never ZERO mpz_mod_ui(mody, Z, flowZ*2); // do { while ( f <= g%(1+mpz_get_ui(mody)) ) // note repeat loop { ///////////////// ///////////// 1st track Amalgamation //////////// // here we OPEN 1st track BLOCK for (w=-1; w< 2; w++ ) // writing to std & mirror tracks - begin primary BLOCK for (j=0; abs(j) < mpz_get_ui(modY); j++) { // Let's open PRIMARY track notes if ( w ) track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,(w+1),realejo[z]+(j%3)+(3*(j%3))-floor(j/2)+(12*w),75+(25*mpz_get_ui(modY)))); else track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,(w+1),0,0)); ///////////// 2nd track Amalgamation (inside primary track) ////////////// // open SECONDARY trackz for (x=0; abs(x) <= mpz_get_ui(modYY) ; x-=y) { mpz_nextprime (Z, Z); mpz_mod_ui(moda, Z, flowZ); // determine duration of note arpflow = mpz_get_ui(moda); /// now sync primary track duration ! longflow += arpflow; // PLAY 2nd track notes if ( j ) _track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,3+(w+1),realejo[z]+(x%3)+(3*(x%3))-floor(x/2)+(6*w),80+(20*mpz_get_ui(modYY)))); else _track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,3+(w+1),0,0)); ///////////// 3rd track Amalgamation [ inside 2nd track ] ///////////// if ( x ) { __track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,6+(w+1),realejo[z]+(i%3)+(3*(i%3))-floor(i/2)+y*(3*w),70+(30*mpz_get_ui(modYYY)))); __track[w+1]->addEvent(new MIDI::ChannelEvent( (a*arpflow),MIDI_CHEVENT_NOTEOFF,6+(w+1),realejo[z]+(i%3)+(3*(i%3))-floor(i/2)+y*(3*w),0)); } else { __track[w+1]->addEvent(new MIDI::ChannelEvent(0,MIDI_CHEVENT_NOTEON,6+(w+1),0,0)); __track[w+1]->addEvent(new MIDI::ChannelEvent( (a*arpflow),MIDI_CHEVENT_NOTEOFF,6+(w+1),0,0)); } } // NOW, close 2nd track for (x=0; abs(x) <= mpz_get_ui(modYY) ; x-=y) if ( j ) _track[w+1]->addEvent(new MIDI::ChannelEvent( (a*arpflow),MIDI_CHEVENT_NOTEOFF,3+(w+1),realejo[z]+(x%3)+(3*(x%3))-floor(x/2)+(6*w),0)); else _track[w+1]->addEvent(new MIDI::ChannelEvent( (a*arpflow),MIDI_CHEVENT_NOTEOFF,3+(w+1),0,0)); ///////////////// also close 1st track notes if ( w ) track[w+1]->addEvent(new MIDI::ChannelEvent((a*longflow),MIDI_CHEVENT_NOTEOFF,(w+1),realejo[z]+(j%3)+(3*(j%3))-floor(j/2)+(12*w),0)); else track[w+1]->addEvent(new MIDI::ChannelEvent((a*longflow),MIDI_CHEVENT_NOTEOFF,(w+1),0,0)); longflow = 0; // reinitilize sync counter // Hm. } f++; } // note repeat loop //} while ( f <= g%mpz_get_ui(mody) ); // note repeat loop //////////////// /// Finish AMALGAMATION //////////////// wheee time to mess around mpz_nextprime(Z, Z); mpz_add(mody, modYYY, Z); // mix values to force composite mpz_mod_ui(mody, mody, 3); // mess around y=flow direction /// until get EVEN result if ( mpz_cmp_ui(mody, 0) != 0 ) // meanwhile, y *= -1; // ................revert increment !! // trying to give more chance of melody variation; // continue Amalgamation for next note in realejo[] // a.k.a. [next z]; } // Amalgamation block - next phrase //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NOW that we completed Amalgamation of notes stored in realejo[] //////////////////////// it's time to create new phrases and REpopulate realejo[] matrix, // or just modify it partially.... mpz_nextprime(Z, Z); mpz_add(Z, Z, n); // try force composite so nully can be even number mpz_mod_ui(nully, Z, 3); // decide repopulation of realejo[] if ( !counter ) g++; // first time, ignition to Amalgamation loop; if ( counter <= mpz_get_ui(nully) ) { // then we use it as a counter for number of spinz mojo += y*(0.0314); // we skip first phrase loop // because it usually sux. :P counter = 0; // reset Amalgamation counter ROOTZ += y*mpz_get_ui(nully); // try to 'slide' root note // in order to vary melody // == ( regen completely all notes in realejo[] ) mpz_add_ui(n, n, 1); mpz_nextprime(Z, n); mpz_mod_ui(mody, Z, AMALGAMATION); noty=mpz_get_ui(mody); if ( noty%2 ) noty++; for (z=0;z => now adds 'nextprime' of "N" ; // goal is to "bypass" // Golden Sequence periodic properties; // mpz_add(itt, next, prev); mpz_set(prev, next); mpz_set(next, itt); mpz_nextprime(Z, Z); // now apply modulus to determine increment. . . mpz_mod_ui(mody, Z, MODULUS); // adjust calcz interval based on kewl scale formulae note += (mpz_get_ui(mody)*2) + \ (floor(mpz_get_ui(mody)/7)*3)+ \ (floor(mpz_get_ui(mody)/9)*2); // store note interval on realejo[] // y determines flow ; // ( increment or decrement ) realejo[z] = ROOTZ + note*y; //+(y*2); } gmp_printf("-*-", n, noty); // DEBUGy counter++; // spinz the loopZ! } // partially modified realejo[] phrase, // continue to Amalgamation loop // that will write notes to MIDI } // MAIN LOOP, reached cmdline param 2 ( ending n-Fib ) ////// When n-Fib reaches the desired interval... // We will issue an END OF TRACK event for each track, // then we will associate each track full of notes // with the file datastructure and write the file to disk. /////////////////////////////////// -EOF- all tracks ///////////////////////////////////// // END melody trackz for (w=0; w<=2; w++ ) { // writing to std & mirror tracks track[w]->addEvent(new MIDI::MetaGenericEvent(0,MIDI_METAEVENT_ENDOFTRACK,0)); _track[w]->addEvent(new MIDI::MetaGenericEvent(0,MIDI_METAEVENT_ENDOFTRACK,0)); __track[w]->addEvent(new MIDI::MetaGenericEvent(0,MIDI_METAEVENT_ENDOFTRACK,0)); } /////////////// NOW WE MUST INSERT THE TRACKS ON THE FILE datastructure ////////// /////// INSERT tracks on MIDI file if ( argc > 5 && atoi(argv[5]) < 0 ) { // only enable mirror tracks // when fifth cmdline param is negative for (w=0; w<=2; w++ ) // PRIMARY + their transposed mirrors file.addTrack(track[w]); for (w=0; w<=2; w++ ) // then 2nd track ++ their transposed mirrors file.addTrack(_track[w]); for (w=0; w<=2; w++ ) // && also 3rd with their transposed mirrors file.addTrack(__track[w]); } else { file.addTrack(track[0]); file.addTrack(_track[0]); file.addTrack(__track[0]); } printf("\n\nGonna write MIDI file to disk*\n"); file.write(); // flush to disk everything we done printf("\n\nDONE we did it - in => %d spinz¡\n", g); } //// END of 'Lyra' mathMuzic Fraktwerk machine; ///// by GUSTAVO L CONTE INFORMATICA ME [2015-2018] //// Feel free to share toughts or send questions: suporte@gu.pro.br /// https://gu.pro.br/Lyra -> Here be dragonz; // MAY THE SOURCE BE WITH YOU. ALWAYS.