Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 498
» Latest member: VikRam025
» Forum threads: 2,851
» Forum posts: 26,700

Full Statistics

Latest Threads
Audio storage, stereo swi...
Forum: Programs
Last Post: VikRam025
7 hours ago
» Replies: 3
» Views: 281
Who wants to PLAY?
Forum: QBJS, BAM, and Other BASICs
Last Post: a740g
9 hours ago
» Replies: 5
» Views: 107
Most efficient way to bui...
Forum: General Discussion
Last Post: ahenry3068
9 hours ago
» Replies: 9
» Views: 124
QBJS - ANSI Draw
Forum: QBJS, BAM, and Other BASICs
Last Post: madscijr
9 hours ago
» Replies: 4
» Views: 123
_CONSOLEINPUT is blocking
Forum: General Discussion
Last Post: mdijkens
Yesterday, 06:26 PM
» Replies: 6
» Views: 94
Fun with Ray Casting
Forum: a740g
Last Post: a740g
Yesterday, 05:50 AM
» Replies: 10
» Views: 230
Very basic key mapping de...
Forum: SMcNeill
Last Post: a740g
Yesterday, 02:33 AM
» Replies: 1
» Views: 52
Methods in types
Forum: General Discussion
Last Post: bobalooie
Yesterday, 01:02 AM
» Replies: 0
» Views: 57
Cautionary tale of open, ...
Forum: General Discussion
Last Post: doppler
01-16-2025, 10:23 AM
» Replies: 3
» Views: 117
Extended KotD #23 and #24...
Forum: Keyword of the Day!
Last Post: SMcNeill
01-16-2025, 09:51 AM
» Replies: 0
» Views: 54

 
  GAMES (2D/3D) ,gameplays
Posted by: MasterGy - 08-24-2022, 09:52 PM - Forum: MasterGy - Replies (5)

The Big Chase


Terror in the Maze


Evil Spiders


Philippines and the resistants


Fairy Game



download with source code:
https://qb64phoenix.com/forum/showthread.php?tid=686

Print this item

  hacking into the c compiler?
Posted by: madscijr - 08-24-2022, 08:19 PM - Forum: General Discussion - Replies (10)

Disclaimer: I'm not sure if I posted about this specifically - if I did, sorry for the repeat! 

I know the C compiler built into QB64 is "under the hood", and QB64 is not really a C IDE and compiler. 

That said, is there a switch or some hidden setting, so you can type a C program in the editor and get it to compile it to an EXE? 

Taking this in another direction, is there a way to see the "intermediate" C code that is generated when it compiles your QB64 program to an EXE? It would be interesting just to look at, to see what the equivalent C code looks like...

Finally, I was looking at dedicated C compilers and IDEs, looking for something that is super simple to install and use. Has anyone got any experience and/or opinions on any of these for Windows?

cLang
Code Blocks
Dev-C++
Embarcadero C++ Builder
GCC
MinGW
MSYS2
Cygwin
Pelles C
Portable C Compiler (PCC)
Tiny C Compiler
Visual Studio 2022 Community


That's all!

Print this item

  Exiting a FOR/NEXt loop
Posted by: Circlotron - 08-24-2022, 05:40 AM - Forum: General Discussion - Replies (3)

Hi all. First post. I did post a couple of times on Facebook, but now I'm here.
Okay... I have a FOR/NEXT loop that I want to exit if a certain condition occurs. The thing is, if I put a label for it to go to it doesn't do that. It simply resumes on the next line after the loop. I'm using version 2.02

Code: (Select All)
Cls
For x& = 1 To 10
    Print x&
    If x& = 5 Then Exit For: GoTo stuff
Next x&

Print "done"
here: GoTo here

stuff:
Print "exited loop"

Print this item

  The Hexeditor project
Posted by: eoredson - 08-24-2022, 03:24 AM - Forum: Utilities - Replies (40)

The Hexeditor project.

This update represents the final editing of the hex editor.

Program name:
  Hex Editor for DOS & Windows Public Domain BASIC Source Code 2023.

Author name:
  Written by Erik Jon Oredson at eoredson@gmail.com

Program purpose:
  This utility allows fast editing of bytes in a file. Two windows allow for
  editing and scrolling through hex values and ascii values.

Hexed8rW.zip for QB64
Hexxit86.zip for VBdos

[Image: hexedit3.png]



[Image: hexedit.png]


[Image: hexedit2.png]

These files can be found at:

http://www.bit.ly/EriksHexEditor

Print this item

  Petri Dish
Posted by: James D Jarvis - 08-23-2022, 08:37 PM - Forum: Works in Progress - Replies (2)

This is an improvement on a program I posted a couple days ago.  It'll get a some more development at some point. 

The screen is randomly populated with an assortment of microbes. They'll skitter about but they do become tired and bored. If you click the mouse that will excite them and get their attention. You can also adjust the temperature and see how they endure. New microbes will slowly spawn in if the population drops.

The program will end when there are no surviving microbes. 

Code: (Select All)
'petri_dish
'By James D Jarvis
'
' bunch of wandering microbes   in a perti dish
'click on the screen with the left mouse button or drag the mouse around the screen holding hte button down and the ...
'microbes will become more excited and move towards the clicks
'control the temperature with the < and > keys

Dim Shared xmax, ymax
xmax = 1100
ymax = 600
Screen _NewImage(xmax, ymax, 32)
_Title "petri dish"
Randomize Timer
ncells = 20 + Int(Rnd * 100) '<- chnage this as desired
Dim Shared X(ncells), Y(ncells), r(ncells), xv(ncells), yv(ncells), kkr(ncells), kkg(ncells), kkb(ncells), a(ncells)
Dim Shared rt(ncells), lstn(ncells), tmp, cold(ncells), hot(ncells), health(ncells)
'build the cells
For c = 1 To ncells
    X(c) = Int(2 + Rnd * (xmax - 60) / 28) * 30
    Y(c) = Int(2 + Rnd * (ymax - 60) / 28) * 30
    r(c) = 4 + Int(Rnd * 6)
    xv(c) = Int(2 - Rnd * 4)
    yv(c) = Int(2 - Rnd * 4)
    kkr(c) = 150 + Int(Rnd * 100)
    kkg(c) = 150 + Int(Rnd * 100)
    kkb(c) = 150 + Int(Rnd * 100)
    a(c) = 2 + Int(Rnd * 16)
    rt(c) = Int(Rnd * 4) - Int(Rnd * 4)
    lstn(c) = Int(Rnd * 100)
    cold(c) = Int(Rnd * 10) - 5
    hot(c) = Int(Rnd * 30) + Abs(cold(c)) + 15
    health(c) = 100 + Int(Rnd * 100)
Next c
tmp = 20
taptap = 0

Do
    headcount = 0
    Cls
    Locate 1, 1: Print tmp; "ø"
    While _MouseInput
        mouseLeftButton = _MouseButton(1)

        If mouseLeftButton Then
            taptap = taptap + 50
            tapx = _MouseX
            tapy = _MouseY
        End If
    Wend
    _Limit 30
    For c = 1 To ncells

        If health(c) > 0 Then
            headcount = headcount + 1
            draw_microbe X(c), Y(c), r(c), kkr(c), kkg(c), kkb(c), a(c), c

            If Rnd * 10 < 7 Then X(c) = X(c) + xv(c)
            If Rnd * 10 < 7 Then Y(c) = Y(c) + yv(c)
            If yv(c) > 30 Then yv(c) = 27
            If xv(c) > 30 Then xv(c) = 27

            If Rnd * 10 < 3 Then xv(c) = xv(c) * .95
            If Rnd * 10 < 3 Then yv(c) = yv(c) * .95
            If taptap > lstn(c) And tapy < Y(c) Then yv(c) = yv(c) - .5
            If taptap > lstn(c) And tapy > Y(c) Then yv(c) = yv(c) + .5
            If taptap > lstn(c) And tapx < X(c) Then xv(c) = xv(c) - .5
            If taptap > lstn(c) And tapx > X(c) Then xv(c) = xv(c) + .5
            If tatap > 0 And X(c) = tapx And Y(x) = tapy Then health(c) = health(c) + 1


            If X(c) < r(c) * 2 Then xv(c) = xv(c) * -1
            If Y(c) < r(c) * 2 Then yv(c) = yv(c) * -1
            If X(c) > xmax - r(c) * 2 Then xv(c) = xv(c) * -1
            If Y(c) > ymax - r(c) * 2 Then yv(c) = yv(c) * -1

            If tmp < cold(c) Then
                xv(c) = xv(c) * .9
                health(c) = health(c) - 1
                If health(c) < 100 Then kkb(c) = kkb(c) + 1
            End If
            If tmp > hot(c) * .75 And tmp < hot(c) * 1.2 Then
                xv(c) = xv(c) * 1.01
                health(c) = health(c) + 1

            End If
            If tmp > hot(c) * 1.2 Then
                xv(c) = xv(c) * .9
                health(c) = health(c) - 1
                If health(c) < 100 Then kkr(c) = kkr(c) + 1
                If kkr(c) > 255 Then kkr(c) = 255
            End If

        End If
        If health(c) > 200 Then health(c) = 200
        If health(c) = 0 And Rnd * 400 < 10 And temp > cold(c) Then
            X(c) = Int(2 + Rnd * (xmax - 60) / 28) * 30
            Y(c) = Int(2 + Rnd * (ymax - 60) / 28) * 30
            r(c) = 4 + Int(Rnd * 6)
            xv(c) = Int(2 - Rnd * 4)
            yv(c) = Int(2 - Rnd * 4)
            kkr(c) = 150 + Int(Rnd * 100)
            kkg(c) = 150 + Int(Rnd * 100)
            kkb(c) = 150 + Int(Rnd * 100)
            a(c) = 2 + Int(Rnd * 16)
            rt(c) = Int(Rnd * 4) - Int(Rnd * 4)
            lstn(c) = Int(Rnd * 100)
            cold(c) = temp * .35
            hot(c) = temp + 50
            health(c) = 100 + Int(Rnd * 100)
            headcount = headcount + 1
        End If
    Next c
    _Display
    If taptap > 1 Then taptap = taptap - 1
    kk$ = InKey$
    If kk$ = "," Or kk$ = "<" Then tmp = tmp - .1
    If kk$ = "." Or kk$ = ">" Then tmp = tmp + .1
    If headcount = 0 Then
        Locate 5, 5: Print "ALL MICROBES DIED"
        kk$ = Chr$(27)
    End If

Loop Until kk$ = Chr$(27)

Input "PRESS ENER TO continue", any$

Sub draw_microbe (x, y, r, kR, kG, kB, arm, c)
    'draw a crude radial microbe with flagellum
    Draw "C" + Str$(_RGB32(kR, kG, kB))
    If x > xmax - r(c) * 2 Then x = xmax - r(c) * 2
    If y > ymax - r(c) * 2 Then y = ymax - r(c) * 2
    If x < r(c) * 2 Then x = r(c) * 2
    If y < r(c) * 2 Then y = r(c) * 2

    Draw "bm" + Str$(x) + "," + Str$(y)
    rv = Rnd * .2
    For ang = 0 + rt(c) To 360 + rt(c) Step Int(360 / arm) + rv
        wiggle$ = " r" + Str$((r + Int(Rnd * 3)) * .33) + " e" + Str$(1 + Int(Rnd * r(c) / 6))
        wiggle$ = wiggle$ + " r" + Str$((r + Int(Rnd * 3)) * .33) + " e" + Str$(1 + Int(Rnd * r(c) / 6))
        wiggle$ = wiggle$ + " r" + Str$((r + Int(Rnd * 3)) * .33)
        Draw "ta" + Str$(ang) + wiggle$ + "bm" + Str$(x) + "," + Str$(y)
        ' Draw "ta" + Str$(ang) + " r" + Str$(r + Int(Rnd * 3)) + " u" + Str$(1 + Int(Rnd * 3)) + "m" + Str$(x) + "," + Str$(y)
    Next ang

End Sub

Print this item

  Any C programmers wanna help convert code to convert between MIDI + CSV?
Posted by: madscijr - 08-23-2022, 05:41 PM - Forum: Help Me! - Replies (93)

I was looking to have QB64 convert MIDI files to CSV and vice-versa and found some C code that looks like it does the job.

It's just 2 files (asc2mid.c and mid2asc.c) and I figure regular C code with no fancy OO, it should be pretty straightforward to convert to BASIC, right? I did a little C back (waaaay back) in school (never mind that I hated it!) and did some standard JavaScript back in the day, so I should at least be familiar with the syntax. Should be a snap, right?
NOPE!

I feel like I'm reading Greek. There's all sorts of weird stuff going on - variables named with asterisks (pointers?), if/then and loops without begin/end braces, and even GOTO statements, not to mention a lot of statements strung all together on one line. This is painful. I ran the code through a beautifier which sort of helped, but it also did things like put spaces before/after the asterisks which might be part of pointer variable names or whatever they are. I then went through the code line by line to try and make sense of the control structure and move everything inside of begin/end {} and pretty it up. Results are below - but I am not sure what errors I may have introduced by doing this stuff.

Also I don't have a C compiler to test this, though it might come in handy later if I ever hope to get this Raw Input API multi-mouse code working or experiment with writing WAV files from scratch. Which leads me to a second question - QB64 comes with a C compiler "bundled" with it, right? Is there some way to use it to compile straight C programs? 

Is anyone interested in helping make sense of some C code?  :-D

Either way, I'll slog through it eventually, just not as fast. 

Here is the original code, the attached ZIP also includes my attempt at prettifying it... 



"mid2asc.c"
Code: (Select All)
/*
From: http://www.archduke.org/midi/

mid2asc:
Converts midi to ascii. Output can be in one of several formats
determined by command line flags.

Time of an event can be determined by one of
   (i) BA+CR:               Bar number+Crotchet within bar
  (ii) CR:                  Crotchet number from the very start
(iii) DT:                  Delta time from previous event - native midi format
  (iv) FOL[+/-crotchets]:   Time from end of previous note/rest on that track
   (v) SIM[+crotchets]:     Time from start of previous note/rest on that track

  Basic complication of mode (i) is that the Time signature affects
  the interpretation of time, and that time signature can change at
  any time on any track and should affect all tracks.

  Could make it closer to the spec. (e.g., skip over unknown chunk types)
 
  Midi files are going to be ambiguous, e.g. order of some events
  occuring at the same time, or whether choose to use running st mode,
  or whether to choose to use 0x8* or 0x9* for voff when
  velocity=0x40.

  Could print key changes from other tracks as comments in sep mode

  Copyright November 2002 A.P.Selby

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  associated documentation files (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge, publish, distribute,
  sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all copies or
  substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string.h>

#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))

#define MAXLL 10000
#define MAXCH 16
#define MAXNT 128
unsigned char *dat;
int p,siz,pr=0,raw,cro,fol,sep,frpad=9;
int bgn[12][2]={{0,0},{0,1},{1,0},{2,-1},{2,0},{3,0},{3,1},{4,0},{4,1},{5,0},{6,-1},{6,0}};
/* ^ best guess note from pitch relative to keynote: (In C maj/A min this would be: C C# D Eb E F F# G G# A Bb B) */
int maj[14]={0,2,4,5,7,9,11, 12,14,16,17,19,21,23};

void err(char *l){fprintf(stderr,"Error: %s\n",l);exit(1);}
#define assrt(x,y) if(!(x))err(y);

char *note2(int n,int s,int pad){
  static char buf[100][20];
  static int p=0;
  int i;
  p=(p+1)%100;
  buf[p][0]="CDEFGAB"[(n+700000)%7];
  i=1;
  while(s>0){assert(i<19);buf[p][i++]='#';s--;}
  while(s<0){assert(i<19);buf[p][i++]='b';s++;}
  while(n>=7){assert(i<19);buf[p][i++]='\'';n-=7;}
  while(n<0){assert(i<19);buf[p][i++]='-';n+=7;}
  if(pad)while(i<pad&&i<19)buf[p][i++]=' ';
  buf[p][i]=0;
  return buf[p];
}
char *note(int n,int sf,int mi,int pad){
  int a,b,m,a0,b0;
  assert(n>=0&&n<128&&sf>=-128&&sf<=127);
  a0=(4*sf+7000)%7;b0=(sf+7001)/7-1000;/* (a0,b0) = keynote of (sf,mi) in pair form */
  n-=60+maj[a0]+b0;/* subtract keynote in single pitch form */
  m=(n+120000)%12;a=bgn[m][0];b=bgn[m][1];/* look up most likely pair form */
  return note2(a0+a+((n-m)/12)*7,maj[a0]+maj[a]-maj[a0+a]+b0+b,pad);/* evaluate cocycle! */
}
char *key(int sf,int mi,int pad){
  static char buf[100][21];
  static int p=0;
  int i,n;
  p=(p+1)%100;
  assert(sf>=-128&&sf<=127);
  if(mi)sf+=3;
  buf[p][0]="FCGDAEB"[(sf+7001)%7];
  n=(sf+7001)/7-1000;i=1;
  while(n>0){buf[p][i++]='#';n--;}
  while(n<0){buf[p][i++]='b';n++;}
  while(i<pad&&i<20)buf[p][i++]=' ';
  buf[p][i]=0;
  return buf[p];
}
int gcd(int a,int b){if(b==0)return a; else return gcd(b,a%b);}
int sprfrac(char *l,int n,int d,int sum,int pad){
  int a,g,s;
  s=0;
  if(sum){
    a=n/d;if(a){
      s=sprintf(l,"%d",a);n-=a*d;
      if(n==0)goto pad;
      s+=sprintf(l+s,"+");
    }
  }
  g=gcd(n,d);n/=g;d/=g;
  if(d!=1)s+=sprintf(l+s,"%d/%d",n,d); else s+=sprintf(l+s,"%d",n);
pad:
  if(s<pad){memmove(l+pad-s,l,s+1);memset(l,' ',pad-s);s=pad;}
  return s;
}
int sprfrac2(char *li,int n,int d){
  /* Prints the simplest (or near simplest) number x such that (int)(n/x+.5)=d */
  int i,t,dp;
  double m,r,x0,x1;
  char l[100],*l0,*l1;
  if(li)l0=li; else l0=l;
  x0=n/(d+.49);x1=n/(d-.49);l1=l0;
  /* Find minimum dp such that [x0,x1] intersects Z*10^(-dp) */
  for(dp=0,m=1;dp<15;dp++){
    r=floor(x1*m);
    if(r>x0*m){
      t=(int)(r/m);
      l1+=sprintf(l1,"%d",t);r-=t*m;
      if(dp){
    l1+=sprintf(l1,".");
    for(i=0;i<dp;i++){m/=10;t=(int)(r/m);l1+=sprintf(l1,"%d",t);r-=t*m;}
      }
      if((int)(n/atof(l0)+.5)!=d){fprintf(stderr,"Error 2 in prfrac2 n=%d d=%d\n",n,d);exit(1);}
      if(li)return l1-l0; else return printf("%s",l);
    }
    m*=10;
  }
  fprintf(stderr,"Error 1 in prfrac2 n=%d d=%d\n",n,d);exit(1);
}

void need(int n,char *l){
  if(p+n>siz){fprintf(stderr,"Unexpected EOF in %s, p=&%06x n=%d siz=&%06x\n",l,p,n,siz);exit(1);}
}
void skip(int n){need(n,"skip");p+=n;}
void match(char *l){
  int i;
  need(strlen(l),"match");
  for(i=0;l[i];i++)if(l[i]!=dat[p++]){
    fprintf(stderr,"Bad match, p=%X i=%d l=%s &%02X!=&%02X\n",p,i,l,l[i],dat[p-1]);exit(1);
  }
}
int getn(int n,int a){
  int i,t;
  need(n,"getn");
  for(i=0,t=0;i<n;i++)t=(t<<8)+dat[p+i];
  if(a)p+=n;
  return t;
}
int get1(){return getn(1,1);}
int get2(){return getn(2,1);}
int get3(){return getn(3,1);}
int get4(){return getn(4,1);}
int look1(){return getn(1,0);}
int getv(){
  int c,t;
  t=0;
  do{
    need(1,"getv");c=dat[p++];t=(t<<7)+(c&127);
  }while(c&128);
  return t;
}
int getnnodt(int st,int e,int *st1){
  /* Returns the dt to next non-noteoff event (raw=0), or next event (raw=1). return=-1 means end of track. */
  int t,p0,dt,sth;
  dt=0;
  while(p<e){
    dt+=getv();*st1=st;if(raw)return dt;
    p0=p;
    t=look1();if(t>=0x80)st=get1(); else assert(st>=0x80);
    sth=st>>4;
    if(sth==8||(sth==9&&dat[p+1]==0))skip(2); else {p=p0;return dt;}
  }
  return -1;
}

typedef struct {int tt,ch,nt,voff;} noteoffbuf;
int cmp(const void*x,const void*y){return ((noteoffbuf*)x)->tt-((noteoffbuf*)y)->tt;}

int main(int ac,char **av){
  int i,s,t,u,bf,bn,btt,fol1,rest,ch,dt,infinity,ln,mi,maxno,nat,non,ols,prb,help,
    sk,sf,st,sth,tis0,tis1,tis2,tpc,tr,trl,tt,ty,alltrfl,format,tracks,division,tempo,nobp[MAXCH][MAXNT];
  char l[MAXLL],*l1;
  double ert;
  typedef struct {int a,p0,l,e,p,pv,st,dt,tt,et,pt;} trackinfo;
  typedef struct fred {int all,bn,tr;char *l;struct fred *nx;} outline;
  trackinfo *tri;
  noteoffbuf *nob;
  outline *outbuf0,*outbuf;
  FILE *fpi;

  raw=cro=fol=sep=help=0;
  for(i=1;i<ac;i++){
    if(!strncmp(av[i],"-c",2))cro=1;
    if(!strncmp(av[i],"-f",2))fol=1;
    if(!strncmp(av[i],"-r",2))raw=1;
    if(!strncmp(av[i],"-s",2))sep=1;
    if(!strncmp(av[i],"-h",2)||!strncmp(av[i],"--help",6))help=1;
  }
  if(ac<2||help){
    fprintf(stderr,"Usage: mid2asc  [-c] [-f,-r] [-s] midifile > textfile\n\n");
    fprintf(stderr,"   Default timing is to use absolute time determined by BA+CR\n");
    fprintf(stderr,"   and use durations for notes.\n");
    fprintf(stderr,"-c Use absolute crotchets rather than BA+CR to determine time.\n");
    fprintf(stderr,"   Useful if inserting or deleting.\n");
    fprintf(stderr,"-f 'Follow' (take time from start or end of previous note) to determine time.\n");
    fprintf(stderr,"-r \"raw\" format: time determined by DT, and note-off events\n");
    fprintf(stderr,"   are used instead of note durations.\n\n");
    fprintf(stderr,"   Default is to print all tracks merged in chronological order.\n");
    fprintf(stderr,"-s Print all tracks separately.\n");
    exit(1);
  }
  if(fol&&raw){fprintf(stderr,"fol and raw modes cannot be combined\n");exit(1);}
  fpi=fopen(av[ac-1],"rb");if(!fpi){fprintf(stderr,"Couldn't open %s\n",av[ac-1]);exit(1);}
  fseek(fpi,0,SEEK_END);siz=ftell(fpi);rewind(fpi);
  if(pr>=1)printf("# File size %d byte%s\n",siz,siz==1?"":"s");
  dat=(unsigned char*)malloc(siz);if(!dat){fprintf(stderr,"Couldn't malloc %d bytes\n",siz);exit(1);}
  fread(dat,1,siz,fpi);p=0;fclose(fpi);
  maxno=siz/2;
  match("MThd");
  assert(get4()==6);
  format=get2();tracks=get2();division=get2();
  printf("format=%d tracks=%d division=%d\n",format,tracks,division);
  if(division&(1<<15))tpc=48; else tpc=division;
  tri=(trackinfo *)malloc(tracks*sizeof(trackinfo));assert(tri);
  nob=(noteoffbuf *)malloc(maxno*sizeof(noteoffbuf));assert(nob);
  infinity=0x7fffffff;

  for(tr=0;p<siz&&tr<tracks;tr++){
    match("MTrk");trl=get4();
    tri[tr].p0=p;tri[tr].l=trl;tri[tr].e=tri[tr].p0+tri[tr].l;
    p+=trl;
  }

  non=0;/* outside 'if' statement to stop warning */
  if(!raw){
    for(tr=0;tr<tracks;tr++){
      st=0;tt=0;p=tri[tr].p0;
      while(p<tri[tr].e){
    dt=getv();tt+=dt;
    t=look1();if(t>=0x80)st=get1(); else assert(st>=0x80);
    sth=st>>4;ch=st&15;
    if(sth==8||sth==9){
      t=get1();u=get1();
      if(sth==9){if(u)continue; else u=0x40;}
      assert(non<maxno);nob[non].tt=tt;nob[non].ch=ch;nob[non].nt=t;nob[non].voff=u;non++;
      continue;
    }
    if(sth==0xC||sth==0xD){skip(1);continue;}
    if(sth==0xF){
      if(st==0xF0||st==0xF7){skip(getv());continue;}
      if(st==0xFF){skip(1);skip(getv());continue;}
      fprintf(stderr,"Unrecognised status %02x\n",st);exit(1);
    }
    skip(2);
      }
    }
    qsort(nob,non,sizeof(noteoffbuf),cmp);
    for(ch=0;ch<MAXCH;ch++)for(t=0;t<MAXNT;t++)nobp[ch][t]=0;
  }

  nat=0;
  for(tr=0;tr<tracks;tr++){
    p=tri[tr].p=tri[tr].p0;
    t=getnnodt(0,tri[tr].e,&tri[tr].st);tri[tr].a=(t>=0);
    if(tri[tr].a){
      tri[tr].et=tri[tr].pt=0;tri[tr].dt=tri[tr].tt=t;tri[tr].p=p;tri[tr].pv=-1;nat++;
    }
  }
  sf=0;mi=0;/* Initial key C major */
  tis0=4;tis1=4;tis2=(tis0*4*tpc)/tis1;/* Initial time signature 4/4 */
  tempo=500000;/* Default usec/beat (= 120 bpm) */
  btt=0;bn=0;bf=0;ert=0;/* at time btt, bar number was bn (from 0), and part of bar complete was bf/tpc crotchets */
  prb=-1;
  ols=MAXLL*10;outbuf=outbuf0=(outline*)malloc(ols);outbuf->nx=0;
  if(!outbuf){fprintf(stderr,"Couldn't malloc %d bytes (outbuf1)\n",ols);exit(1);}
  while(nat>0){
    tt=infinity;tr=-1;alltrfl=0;
    for(i=0;i<tracks;i++)if(tri[i].a){
      t=tri[i].tt;if(fol&&tri[i].et<t)t=tri[i].et;
      if(t<tt){tr=i;tt=t;}
    }
    assert(tr>=0);
    p=tri[tr].p;t=look1();if(t>=0x80)st=get1(); else st=tri[tr].st;
    sth=st>>4;ch=st&15;
    assert(!(raw==0&&(sth==8||(sth==9&&dat[p+1]==0))));
    rest=(fol&&tri[tr].et<tri[tr].tt);
    fol1=(fol&&tri[tr].et<=tri[tr].tt);
    l1=l;
    if(tt>btt){
      ert+=(double)(tt-btt)*(double)tempo/(double)tpc;
      /* Elapsed crotchets=(btt-tt)/tpc, ticks/bar=tis2 */
      t=tt-btt+bf; bn+=t/tis2; bf=t%tis2; btt=tt;
    }
    if(!sep&&bn!=prb){l1+=sprintf(l1,"\n");prb=bn;}
    if(fol){
      u=0;
      if(fol1)l1+=sprintf(l1,"FOL"); else {
    l1+=sprintf(l1,"SIM");t=tri[tr].tt-tri[tr].pt;if(t){
      assert(t>0);l1+=sprintf(l1,"+");u=sprfrac(l1,t,tpc,1,0);l1+=u;u++;
    }
      }
      while(u<frpad+1){*(l1++)=' ';u++;}
      l1+=sprintf(l1," (");
    }
    if(raw){l1+=sprintf(l1,"DT ");l1+=sprfrac(l1,tri[tr].dt,tpc,1,frpad);l1+=sprintf(l1,"   (");}
    if(cro){l1+=sprintf(l1,"CR ");l1+=sprfrac(l1,tt,tpc,1,4+frpad);l1+=sprintf(l1,"   (");}
    l1+=sprintf(l1,"BA %4d   CR ",bn+1);l1+=sprfrac(l1,bf,tpc,1,frpad);
    if(cro)l1+=sprintf(l1,")");
    if(raw)l1+=sprintf(l1,")");
    if(fol)l1+=sprintf(l1,")");
    l1+=sprintf(l1,"   TR %2d   CH %2d   ",tr,ch+1);
    if(rest){
      l1+=sprintf(l1,"NT  R       ");l1+=sprfrac(l1,tri[tr].tt-tt,tpc,1,frpad);l1+=sprintf(l1,"\n");
      tri[tr].pt=tt;tri[tr].et=tri[tr].tt;goto bp2;
    }
    if(sth==8||sth==9){
      t=get1();u=get1();
      l1+=sprintf(l1,"NT  %s ",note(t,sf,mi,7));
      if(sth==8||(sth==9&&u==0)){
    assert(raw);
    l1+=sprintf(l1,"off");
    if(sth==8&&u!=0x40)l1+=sprintf(l1,"   voff=%d",u);
    l1+=sprintf(l1,"\n");
    goto bp1;
      }
      if(raw)l1+=sprintf(l1,"on"); else {
    assert(ch<MAXCH&&t<MAXNT);
    for(i=nobp[ch][t];i<non;i++)if(nob[i].tt>tt&&nob[i].ch==ch&&nob[i].nt==t)break;
    nobp[ch][t]=i;
    if(i<non){
      l1+=sprfrac(l1,nob[i].tt-tt,tpc,1,frpad);
      tri[tr].pt=tt;tri[tr].et=nob[i].tt;
    }else l1+=sprintf(l1,"infinity");
      }
      if(u!=tri[tr].pv){l1+=sprintf(l1,"   von=%d",u);tri[tr].pv=u;}
      if(!raw&&i<non&&nob[i].voff!=0x40)l1+=sprintf(l1,"   voff=%d",nob[i].voff);
      l1+=sprintf(l1,"\n");
      if(!raw&&i==non)l1+=sprintf(l1,"# Warning tr=%d p=&%X, note never turned off\n",tr,p);
      goto bp1;
    }
    if(sth==0xB){
      t=look1();if(t==7){
    t=get1();u=get1();
    l1+=sprintf(l1,"Channel volume %d\n",u);goto bp1;
      }
    }
    if(sth==0xC){t=get1();l1+=sprintf(l1,"Instrument %d\n",t+1);goto bp1;}
    if(sth==0xF){
      if(st==0xF0||st==0xF7){
    t=getv();l1+=sprintf(l1,"Sysex event &%02X ",st);
    for(i=0;i<t;i++)l1+=sprintf(l1," &%02X",dat[p++]);l1+=sprintf(l1,"\n");
    goto bp1;
      }
      if(st==0xFF){
    ty=get1();ln=getv();need(ln,"Meta");
    if(ty>=1&&ty<=7){
      l1+=sprintf(l1,"Text type %d: \"",ty);
      for(i=0;i<ln;i++){
        t=dat[p++];switch(t){
        case '\t':l1+=sprintf(l1,"\\t");break;
        case '\n':l1+=sprintf(l1,"\\n");break;
        case '\v':l1+=sprintf(l1,"\\v");break;
        case '\f':l1+=sprintf(l1,"\\f");break;
        case '\r':l1+=sprintf(l1,"\\r");break;
        case '\\':l1+=sprintf(l1,"\\\\");break;
        default:if(t!=0)l1+=sprintf(l1,"%c",t);break;
        }
      }
      l1+=sprintf(l1,"\"\n");
      goto bp1;
    }
    if(ty==0x2F){
      assert(ln==0);
      l1+=sprintf(l1,"End of track\n");goto bp1;
    }
    if(ty==0x51){
      assert(ln==3);tempo=get3();
      l1+=sprintf(l1,"Tempo ");l1+=sprfrac2(l1,60*1000000,tempo);l1+=sprintf(l1,"\n");
      alltrfl=1;
      goto bp1;
    }
    if(ty==0x58){
      assert(ln==4);assert(tt==btt);
      tis0=dat[p];tis1=1<<dat[p+1];assrt((tis0*4*tpc)%tis1==0,"New time signature not commensurate with division");
      tis2=(tis0*4*tpc)/tis1;
      l1+=sprintf(l1,"Time signature %d/%d, clocks/mtick %d, crotchets/32ndnote %d\n",tis0,tis1,dat[p+2],dat[p+3]);
      alltrfl=1;
      p+=ln;goto bp1;
    }
    if(ty==0x59){
      assert(ln==2);
      sf=get1();if(sf>=128)sf-=256;mi=get1();
      l1+=sprintf(l1,"Key %s %s\n",key(sf,mi,0),mi?"minor":"major");
      alltrfl=1;
      goto bp1;
    }
    l1+=sprintf(l1,"Meta Event   type &%02X  ",ty);
    for(i=0;i<ln;i++)l1+=sprintf(l1," %d",dat[p++]);l1+=sprintf(l1,"\n");
    goto bp1;
      }
      assert(0);
    }
    if(sth==0xD)sk=1; else sk=2;
    l1+=sprintf(l1,"ST &%02X",st);
    for(i=0;i<sk;i++)l1+=sprintf(l1," &%02X",dat[p++]);l1+=sprintf(l1,"\n");
  bp1:
    tri[tr].dt=getnnodt(st,tri[tr].e,&tri[tr].st);
    if(tri[tr].dt>=0){tri[tr].tt+=tri[tr].dt;tri[tr].p=p;} else {tri[tr].a=0;nat--;}
  bp2:
    if(sep){
      s=l1-l+1;t=sizeof(outline);u=(s+t-1)/t;
      assert((u+1)*t<=MAXLL&&ols>=MAXLL);
      outbuf->tr=tr;outbuf->all=alltrfl;outbuf->bn=bn;outbuf->l=(char*)(outbuf+1);
      if(ols-(u+1)*t<MAXLL){
    ols=MAXLL*10;outbuf->nx=(outline*)malloc(ols);
    if(!outbuf->nx){fprintf(stderr,"Couldn't malloc %d bytes (outbuf2)\n",ols);exit(1);}
      } else {
    outbuf->nx=outbuf+u+1;ols-=(u+1)*t;
      }
      memcpy(outbuf->l,l,s);outbuf=outbuf->nx;outbuf->nx=0;
    } else printf("%s",l);
  } /* main loop */

  if(sep)for(tr=0;tr<tracks;tr++){
    printf("# TRACK %d\n",tr);
    prb=-1;
    for(outbuf=outbuf0;outbuf->nx;outbuf=outbuf->nx){
      if((outbuf->all||outbuf->tr==tr)&&outbuf->bn!=prb){printf("\n");prb=outbuf->bn;}
      if(outbuf->all&&outbuf->tr!=tr)printf("# ");
      if(outbuf->all||outbuf->tr==tr)printf("%s",outbuf->l);
    }
    printf("\n");
  }
 
  printf("# Successfully parsed\n");
  printf("# Duration = %g seconds\n",ert/1000000);
  return 0;
}



"asc2mid.c"
Code: (Select All)
/*
From: http://www.archduke.org/midi/

asc2mid:
Converts ascii to midi. Ascii is in format output by mid2asc in one
of several modes, or it can be in a more mixed format.

Time of an event can be determined by one of
   (i) BA+CR:               Bar number+Crotchet within bar
  (ii) CR:                  Crotchet number from the very start
(iii) DT:                  Delta time from previous event - native midi format
  (iv) FOL[+/-crotchets]:   Time from end of previous note/rest on that track
   (v) SIM[+crotchets]:     Time from start of previous note/rest on that track

  Basic complication of mode (i) is that the Time signature affects
  the interpretation of time, and that time signature can change at
  any time on any track and should affect all tracks.

  At the moment it requires lines of each track to be in chronological
  order which can make it slightly awkward to change the track of a
  note in sep=1 mode. If all file were in mode (ii), then it could
  sort it out for you, I suppose. Or the user could sort the lines
  first.

  Should make more case insensitive?

  MIT License

  Copyright November 2002 A.P.Selby

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  associated documentation files (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge, publish, distribute,
  sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all copies or
  substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>

#define MIN(x,y) ((x)<(y)?(x):(y))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MAXNOB 10000

char *inbuf,*inend,*ip;
int tr,infinity;
int maj[14]={0,2,4,5,7,9,11, 12,14,16,17,19,21,23};
typedef struct {int l,st,von,bt,pt,et,sta,bn,cr,tt,ln,ip,op;unsigned char *out;} trackinfo;
trackinfo *tri;
/*
  trackinfo:
  st = midi state (state of previous midi event laid down)
  bt = time of last event laid down
  pt = start time of last note or rest
  et = end time of last note or rest
  sta = track state
     state 0 ==> Need to read time of new line
     state 1 ==> Time of next line specified by tt
     state 2 ==> Time of next line specified by bn,cr; tt is valid if there is no time sig. change before it
     state 3 ==> Track at an end - no more lines on this track
  bn,cr,tt time of next event defined by (bn,cr) or tt according to state
  ip = integer input pointer (inbuf+.ip is actual pointer)
  ln = input line number
  out = pointer to start of output buffer (can change when gets resized)
  op = integer output pointer (.out+.op is actual pointer)
  l = allocated size of output buffer
  von = volume of last note-on event
*/

void err(char *l){
  if(tr==-1)fprintf(stderr,"Error: %s\n",l); else fprintf(stderr,"Error: %s at line %d:\n%s\n",l,tri[tr].ln,ip);
  exit(1);
}
#define assrt(x,y) if(!(x))err(y);

char *getns(char *l){while(*l==' ')l++; return l;}

int strtoi(char *l,char **e){
  int b,n;
  char *l1,*l2;
  l1=l;while(*l1!=0&&*l1!='&'&&!isdigit(*l1)&&strncmp(l1,"infinity",8))l1++;
  if(strncmp(l1,"infinity",8)==0)return infinity;
  if(*l1=='&'){l1++;b=16;} else if(*l1=='0'&&l1[1]=='x'){l1+=2;b=16;} else b=10;
  n=strtol(l1,&l2,b);
  if(e){if(l2==l1)*e=l; else *e=l2;}
  return n;
}

/*
int getfrn(char *l,int d){
  int a,b,c;
  char *l1;
  a=strtoi(l,&l1);
  if(l1[0]=='+')b=strtoi(l1+1,&l1); else {b=a;a=0;}
  if(a==infinity||b==infinity)return infinity;
  if(l1[0]=='/')c=strtoi(l1+1,0); else c=1;
  b+=a*c;
  assrt(d%c==0,"fraction not allowed");
  return b*(d/c);
}
*/
int getfrn(char *l,int d){
  int a,b,t;
  char *l1;
  t=0;
  do{
    a=strtoi(l,&l1);if(l1==l)break;
    if(a==infinity)return infinity;
    if(l1[0]=='/')b=strtoi(l1+1,&l1); else b=1;
    a*=d;assrt(a%b==0,"fraction not allowed");t+=a/b;
    l=l1;
  }while(l[0]=='+');
  return t;
}

int strton(char *l,char **e){
  int n;
  char *l1,*l2;
  while(*l==' ')l++;
  l1="CDEFGABR";l2=strchr(l1,toupper(*l));assrt(l2,"unrecognised note");
  if(l2-l1==7){*e=l+1;return -1;}
  n=60+maj[l2-l1];l++;
  while(*l=='#'){n++;l++;}
  while(*l=='b'){n--;l++;}
  while(*l=='\''){n+=12;l++;}
  while(*l=='-'){n-=12;l++;}
  assrt(n>=0&&n<128,"note out of range");
  *e=l;return n;
}

void acc(int p){
  int nl;
  unsigned char *new;
  if(p<=tri[tr].l)return;
  if(tri[tr].l==0)nl=10240; else nl=tri[tr].l*2;
  if(nl<p)nl=p;
  new=(unsigned char *)malloc(nl);if(!new)err("Couldn't malloc output track space");
  if(tri[tr].out){memcpy(new,tri[tr].out,tri[tr].op);free(tri[tr].out);}
  tri[tr].out=new;tri[tr].l=nl;
}
void putn(int n,int t){
  acc(tri[tr].op+n);
  while(n>0)tri[tr].out[tri[tr].op++]=(t>>(--n)*8)&255;
}
void put1(int t){putn(1,t);}
void put2(int t){putn(2,t);}
void put3(int t){putn(3,t);}
void put4(int t){putn(4,t);}
void putv(int t){
  int n,u;
  assrt(t>=0&&t<0x10000000,"variable number out of range (event out of sequence?)");
  for(n=1,u=t;u>=128;n++)u>>=7;
  acc(tri[tr].op+n);
  while(n>0)tri[tr].out[tri[tr].op++]=((t>>(--n)*7)&127)|128;
  tri[tr].out[tri[tr].op-1]&=~128;
}
void putstn(char *l,int s){acc(tri[tr].op+s);memcpy(tri[tr].out+tri[tr].op,l,s);tri[tr].op+=s;}
void putst(char *l){putstn(l,strlen(l));}

char *getl(int tr){
  char *l;
  l=inbuf+tri[tr].ip;if(tri[tr].ln>0)l+=strlen(l)+1;
  tri[tr].ln++;
  while(l<inend&&(l[0]==0||l[0]=='#'||strncmp(l,"format=",7)==0)){l+=strlen(l)+1;tri[tr].ln++;}
  tri[tr].ip=l-inbuf;
  if(l<inend)return l; else return 0;
}

typedef struct {int tr,tt,ch,nt,voff;} noteoffbuf;
int main(int ac,char **av){
  int d,i,n,s,t,cr,bn,ch,nxt,mi,tr0,non,sf,st,rest,tis0,tis1,tis2,tpc,text,tt,siz,format,tracks,division;
  char *l1,*l2,*l3;
  noteoffbuf *nob;
  FILE *fpi;

  if(ac<2){
    fprintf(stderr,"Usage: asc2mid textfile > midifile\n\n");
    fprintf(stderr," Time of an event can be determined by one of\n");
    fprintf(stderr,"   (i) BA+CR:               Bar number+Crotchet within bar\n");
    fprintf(stderr,"  (ii) CR:                  Crotchet number from the very start\n");
    fprintf(stderr," (iii) DT:                  Delta time from previous event - native midi format\n");
    fprintf(stderr,"  (iv) FOL[+/-crotchets]:   Time from end of previous note/rest\n");
    fprintf(stderr,"   (v) SIM[+crotchets]:     Time from start of previous note/rest\n");
    exit(1);
  }
  fpi=fopen(av[1],"r");if(!fpi){fprintf(stderr,"Couldn't open %s\n",av[1]);exit(1);}
  fseek(fpi,0,SEEK_END);siz=ftell(fpi);rewind(fpi);
  fprintf(stderr,"File size %d byte%s\n",siz,siz==1?"":"s");
  inbuf=(char*)malloc(siz+1);if(!inbuf){fprintf(stderr,"Couldn't malloc %d bytes (inbuf)\n",siz+1);exit(1);}
  n=fread(inbuf,1,siz,fpi);assert(n<=siz);siz=n;inbuf[siz]=0;inend=inbuf+siz;fclose(fpi);
  for(i=0;i<siz;i++)if(inbuf[i]=='\n')inbuf[i]=0;
 
  ip=inbuf;tr-=1;
  while(ip<inend&&strncmp(ip,"format=",7))ip+=strlen(ip)+1;
  if(ip==inend)err("Didn't find format line");
  l1=strstr(ip,"format=");assert(l1);format=strtoi(l1+7,0);
  l1=strstr(ip,"tracks=");assert(l1);tracks=strtoi(l1+7,0);
  l1=strstr(ip,"division=");assert(l1);division=strtoi(l1+9,0);
  fprintf(stderr,"format=%d tracks=%d division=%d\n",format,tracks,division);

  nob=(noteoffbuf *)malloc(MAXNOB*sizeof(noteoffbuf));assert(nob);
  tri=(trackinfo*)malloc((tracks+1)*sizeof(trackinfo));assert(tri); /* Track number <tracks> is for the preamble */
  for(i=0;i<=tracks;i++){
    tri[i].out=0;tri[i].ip=0;tri[i].op=(i<tracks?8:0);/* leave 8 bytes for MTrk, length */
    tri[i].l=0;tri[i].ln=0;
    tri[i].bt=tri[i].pt=tri[i].et=0;tri[i].von=100;
    tri[i].bn=tri[i].cr=tri[i].tt=0;tri[i].sta=0;
    tri[i].st=-1;
  }
 
  if(division&(1<<15))tpc=48; else tpc=division;
  infinity=0x7fffffff;
  tr=tracks;putst("MThd");put4(6);put2(format);put2(tracks);put2(division);
 
  tis0=4;tis1=4;tis2=(tis0*4*tpc)/tis1;/* Initial time signature 4/4 */
  tt=0;bn=0;cr=0;
  /* (tt,bn,cr) are always kept in step, and it is guaranteed that there
     are no time sig. changes between tt and the present new time. */
  non=0;/* number of pending note-off events */
  while(1){
    nxt=infinity;tr0=-1;
    for(tr=0;tr<tracks;tr++){
      if(tri[tr].sta==3)goto nl0;
      if(tri[tr].sta==0){
    do{
      ip=getl(tr);if(!ip){tri[tr].sta=3;goto nl0;}
      ip=getns(ip);
      l1=strstr(ip,"TR ");if(!l1)err("Expect TR");
    }while(strtoi(l1+3,0)!=tr);
    if(strncmp(ip,"DT ",3)==0){tri[tr].tt=tri[tr].bt+getfrn(ip+3,tpc);tri[tr].sta=1;goto ok0;}
    if(strncmp(ip,"FOL",3)==0||strncmp(ip,"SIM",3)==0){
      tri[tr].tt=tri[tr].pt;
      if(ip[0]=='F'){
        if(tri[tr].et>=0)tri[tr].tt=tri[tr].et; else
          fprintf(stderr,"Warning - FOL reverts to SIM following a DT-defined or infinite length note/rest\n");
      }
      if(ip[3]=='+')tri[tr].tt+=getfrn(ip+4,tpc);
      if(ip[3]=='-')tri[tr].tt-=getfrn(ip+4,tpc);
      tri[tr].sta=1;goto ok0;
    }
    if(strncmp(ip,"CR ",3)==0){
      tri[tr].tt=getfrn(ip+3,tpc);
      tri[tr].sta=1;goto ok0;
    }
    if(strncmp(ip,"BA ",3)==0){
      tri[tr].bn=strtoi(ip+3,&l1)-1;
      l1=getns(l1);if(strncmp(l1,"CR ",3))err("Expect CR after BA");
      tri[tr].cr=getfrn(l1+3,tpc);
      tri[tr].sta=2;goto ok0;
    }
    err("Expected time specification (DT, FOL, SIM, CR, or BA) at start of line");
      }
    ok0:
      if(tri[tr].sta==2)tri[tr].tt=tt+(tri[tr].bn-bn)*tis2+tri[tr].cr-cr;
      if(tri[tr].tt<nxt){nxt=tri[tr].tt;tr0=tr;}
    nl0:
      tr=tr;/* because ISO C forbids label at end of compound statement, apparently */
    }
    if(tr0==-1)break;
    tr=tr0;ip=inbuf+tri[tr].ip;tri[tr].sta=0;
   
    text=(strstr(ip,"Text")!=0);
    /* Need to know if Text line, since otherwise the quoted string
       could cause a false match with some other key word */
    t=nxt-tt+cr; bn+=t/tis2; cr=t%tis2; tt=nxt;
    /* At this point, tt=time of next non-note-off event.
       Have to lay down note-off events which have been bypassed. */
    tr0=tr;
    for(i=0;i<non&&nob[i].tt<=tt;i++){
      tr=nob[i].tr;putv(nob[i].tt-tri[tr].bt);tri[tr].bt=nob[i].tt;
      if(nob[i].voff!=0x40){
    st=0x80+nob[i].ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
    put1(nob[i].nt);put1(nob[i].voff);
      }else{
    st=0x90+nob[i].ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
    put1(nob[i].nt);put1(0);
      }
    }
    if(i>0){non-=i;memmove(nob,nob+i,non*sizeof(noteoffbuf));}
    tr=tr0;
    rest=0;if(!text){l1=strstr(ip,"NT ");if(l1)rest=(toupper(*(getns(l1+3)))=='R');}
    if(!rest){putv(tt-tri[tr].bt);tri[tr].bt=tt;}
    if(text){
      put1(tri[tr].st=0xFF);
      l1=strstr(ip,"type");assrt(l1,"missing 'type' in text line");t=strtoi(l1+4,0);put1(t);
      l1=strchr(l1+4,'"');assrt(l1,"missing opening quote in text line");l1++;
      l2=strrchr(l1,'"');assrt(l2,"missing closing quote in text line");
      for(i=s=0;i<l2-l1;i++){
    t=l1[i];
    if(t=='\\'&&i<l2-l1-1){
      t=l1[++i];
      if(t=='t')t=9;
      if(t=='n')t=10;
      if(t=='v')t=11;
      if(t=='f')t=12;
      if(t=='r')t=13;
    }
    l1[s++]=t;
      }
      putv(s);putstn(l1,s);
      continue;
    }
    l1=strstr(ip,"CH ");assrt(l1,"missing channel number");ch=strtoi(l1+3,0)-1;assrt(ch>=0&&ch<16,"channel number out of range");
    l1=strstr(ip,"Time signature");if(l1){
      tis0=strtoi(l1+14,&l1);tis1=strtoi(l1+1,0);assrt((tis0*4*tpc)%tis1==0,"New time signature not commensurate with division");
      tis2=(tis0*4*tpc)/tis1;
      put1(tri[tr].st=0xFF);
      put1(0x58);putv(4);put1(tis0);
      for(i=0,n=tis1;n>1;i++)n>>=1;put1(i);
      l2=strstr(ip,"clocks/mtick");assrt(l2,"missing clocks/mtick");put1(strtoi(l2+12,0));
      l2=strstr(ip,"crotchets/32ndnote");assrt(l2,"missing crotchets/32ndnote");put1(strtoi(l2+18,0));
      continue;
    }
    l1=strstr(ip,"Channel volume");if(l1){
      st=0xB0+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      t=strtoi(l1+14,0);assrt(t>=0&&t<128,"channel volume out of range");put1(7);put1(t);
      continue;
    }
    l1=strstr(ip,"Instrument");if(l1){
      st=0xC0+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      t=strtoi(l1+10,0)-1;assrt(t>=0&&t<128,"instrument out of range");put1(t);
      continue;
    }
    l1=strstr(ip,"Sysex event");if(l1){
      put1(tri[tr].st=strtoi(l1+11,&l1));
      n=0;l2=l1;while(1){strtoi(l2,&l3);if(l3==l2)break;l2=l3;n++;}
      putv(n);for(l2=l1;n>0;n--)put1(strtoi(l2,&l2));
      continue;
    }
    l1=strstr(ip,"End of track");if(l1){
      put1(tri[tr].st=0xFF);
      put1(0x2F);put1(0);
      continue;
    }
    l1=strstr(ip,"Tempo");if(l1){
      put1(tri[tr].st=0xFF);
      n=(int)(60*1000000./atof(l1+5)+.5);assrt(n>=0&&n<=0xFFFFFF,"tempo out of range");
      put1(0x51);putv(3);put3(n);
      continue;
    }
    l1=strstr(ip,"Key ");if(l1){
      put1(tri[tr].st=0xFF);
      l1=getns(l1+4);l2="FCGDAEB";l3=strchr(l2,toupper(*l1));assrt(l3,"unrecognised key");sf=l3-l2-1;
      do{l1++;sf+=7*((*l1=='#')-(*l1=='b'));}while(*l1=='#'||*l1=='b');
      l2=strstr(l1," major");l3=strstr(l1," minor");assrt((l2!=0)^(l3!=0),"missing minor/major in key");
      mi=(l3!=0);sf-=3*mi;
      put1(0x59);putv(2);put1(sf&255);put1(mi);
      continue;
    }
    l1=strstr(ip,"Meta Event");if(l1){
      put1(tri[tr].st=0xFF);
      put1(strtoi(l1+10,&l1));
      n=0;l2=l1;while(1){strtoi(l2,&l3);if(l3==l2)break;l2=l3;n++;}
      putv(n);for(l2=l1;n>0;n--)put1(strtoi(l2,&l2));
      continue;
    }     
    l1=strstr(ip,"ST ");if(l1){
      st=strtoi(l1+3,&l1);if(st!=tri[tr].st||((st&0xF0)==0xF0))put1(tri[tr].st=st);
      while(1){n=strtoi(l1,&l2);if(l2==l1)break;l1=l2;put1(n);}
      continue;
    }
    l1=strstr(ip,"NT ");if(l1){
      tri[tr].pt=tt;tri[tr].et=-1;
      n=strton(l1+3,&l1);l1=getns(l1);
      if(strncmp(l1,"on",2)==0){
    assrt(n>=0,"can't have rest and 'on'");
    st=0x90+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
    l2=strstr(l1,"von=");if(l2)tri[tr].von=strtoi(l2+4,0);
    assrt(tri[tr].von>=1&&tri[tr].von<128,"von out of range");
    put1(n);put1(tri[tr].von);
    continue;
      }
      if(strncmp(l1,"off",3)==0){
    l2=strstr(l1,"voff=");if(l2)t=strtoi(l2+5,0); else t=0x40;
    assrt(t>=0&&t<128,"voff out of range");
    if(t!=0x40){/* not most efficient coding, but most likely to mimic convention used by others(?) */
      st=0x80+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      put1(n);put1(t);
    }else{
      st=0x90+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      put1(n);put1(0);
    }
    continue;
      }
      d=getfrn(l1,tpc);if(d<infinity){nxt=tt+d;tri[tr].et=nxt;}
      if(rest)continue;
      assert(n>=0);
      l2=strstr(l1,"von=");if(l2)tri[tr].von=strtoi(l2+4,0);
      assrt(tri[tr].von>=1&&tri[tr].von<128,"von out of range");
      st=0x90+ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      put1(n);put1(tri[tr].von);
      if(d<infinity){
    l2=strstr(l1,"voff=");if(l2)t=strtoi(l2+5,0); else t=0x40;
    for(i=0;i<non;i++)if(nob[i].ch==ch&&nob[i].nt==n){
      fprintf(stderr,"Warning - overlapping note at line %d:\n%s\n",tri[tr].ln,ip);
      /*
        memmove(nob+i,nob+i+1,(non-(i+1))*sizeof(noteoffbuf));non--;
        Can't necessarily delete note-off event when notes overlap because
        some devices might stack the extra soundings of same note, and so
        deleting this event may result in a note stuck on.
      */
      break;
    }
    assrt(non<MAXNOB,"Note-off buffer full");
    for(i=0;i<non&&nob[i].tt<=nxt;i++);
    memmove(nob+i+1,nob+i,(non-i)*sizeof(noteoffbuf));non++;
    nob[i].tr=tr;nob[i].tt=nxt;nob[i].ch=ch;nob[i].nt=n;nob[i].voff=t;
      }
      continue;
    }
    fprintf(stderr,"Unrecognised line %d:\n%s\n",tri[tr].ln,ip);exit(1);
  }/* main loop */
  for(i=0;i<non;i++){
    tr=nob[i].tr;putv(nob[i].tt-tri[tr].bt);tri[tr].bt=nob[i].tt;
    if(nob[i].voff!=0x40){
      st=0x80+nob[i].ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      put1(nob[i].nt);put1(nob[i].voff);
    }else{
      st=0x90+nob[i].ch;if(st!=tri[tr].st)put1(tri[tr].st=st);
      put1(nob[i].nt);put1(0);
    }
  }
  if(i>0){non-=i;memmove(nob,nob+i,non*sizeof(noteoffbuf));}
  fprintf(stderr,"Successfully parsed\n");
  fwrite(tri[tracks].out,1,tri[tracks].op,stdout);
  for(tr=0;tr<tracks;tr++){
    t=tri[tr].op;tri[tr].op=0;putst("MTrk");put4(t-8);
    if(tri[tr].out)fwrite(tri[tr].out,1,t,stdout); else assert(t==0);
  }
  return 0;
}



Attached Files
.zip   convert-midi.zip (Size: 26.28 KB / Downloads: 60)
Print this item

Photo Ellipse trouble
Posted by: james2464 - 08-23-2022, 03:29 PM - Forum: Help Me! - Replies (14)

I want to make a program that creates dots in the shape of an ellipse.

So not knowing about the math involved I assumed it would be fairly simple.   Then I googled and youtubed and that didn't help much.   I did end up with a mild headache though.

There's a fancy formula that stands out from everything I've been learning, but I really don't know how to use it properly.   So I thought I'd ask here, in case anyone knows.

The formula is:


x2/a2 + y2/b2 = 1     ( x-squared over a-squared + y-squared over b-squared = 1)


It's been too long since I've worked with algebra so I'm just unsure of how to solve for x.    The "=1" part is not helping at all  Big Grin


I've learned the basic principles of the ellipse itself, and so here is an example I'm working with:


The ellipse is 200 wide (2a) by 100 tall  (2b)

a = 100
b = 50
located at position 0,0

I know the distance between the focal points is 86.603 in this case

If I could understand how to find a simple x,y point, I'm sure I'd be on my way to writing a program immediately.

The top center point in this case is x0, y50.   So I'm wondering what the x value is if y=48.   Or if y=46.   Or all the way to y=2.    

Cheers,
James

Print this item

  3D Disco Lights
Posted by: SierraKen - 08-23-2022, 04:52 AM - Forum: Programs - Replies (4)

I doubled up my Anemometer and turned them into disco lights! Plus I added a random setting to make them go at a random direction and speed if random mode is turned on. To turn it on press the Space Bar as it says in the title bar. If you press the Space Bar and it doesn't work, press it again a few more times, sometimes it's caught up in a loop I think. To turn random mode off press it again. Without random mode you can use the mouse wheel to change the speed and direction of the lights. Tell me what you think, thanks.

Code: (Select All)
Screen _NewImage(800, 600, 32)
start:
t = (_Pi / 2) * 100
t2 = ((11 * _Pi) / 6) * 100
t3 = ((7 * _Pi) / 6) * 100
t6 = (_Pi / 2) * 100
t5 = ((11 * _Pi) / 6) * 100
t4 = ((7 * _Pi) / 6) * 100

cc = 200
cc4 = 200

Do
    _Limit 50
    While _MouseInput: wheel = wheel + _MouseWheel: Wend
    a$ = InKey$
    If (a$ = " " Or a$ = "r" Or a$ = "R") And rand = 1 Then
        rand = 0
        a$ = ""
    End If
    If (a$ = " " Or a$ = "r" Or a$ = "R") And rand = 0 Then
        rand = 1
        a$ = ""
        w = 1
    End If
    If wheel > 5 Then wheel = 5
    If wheel < -5 Then wheel = -5
    If rand = 0 Then
        w = wheel
        _Title "Disco Lights by SierraKen - Use Mouse Wheel - Space Bar to turn random mode on"
    End If
    If rand = 1 Then
        lights = Rnd * 100
        If lights > 95 Then w = Int(Rnd * 5) - 5
        _Title "Disco Lights by SierraKen - Use Mouse Wheel - Space Bar to turn random mode off"
    End If

    If t2 < 0 Then GoTo start:
    x = (Sin(t) * 20) * (_Pi * 2) + 400
    y = (Cos(t) * 10) * (_Pi / 2) + 200
    r = (Cos(t) * 180) / _Pi / 1.5 + 50
    t = t - (.25 + w / 10)
    x2 = (Sin(t2) * 20) * (_Pi * 2) + 400
    y2 = (Cos(t2) * 10) * (_Pi / 2) + 200
    r2 = (Cos(t2) * 180) / _Pi / 1.5 + 50
    t2 = t2 - (.25 + w / 10)
    x3 = (Sin(t3) * 20) * (_Pi * 2) + 400
    y3 = (Cos(t3) * 10) * (_Pi / 2) + 200
    r3 = (Cos(t3) * 180) / _Pi / 1.5 + 50
    t3 = t3 - (.25 + w / 10)
    For S = .25 To r Step .1
        cc = cc - .25
        Circle (x, y), S, _RGB32(cc, cc, 100 + cc)
    Next S
    cc = 200
    For S = .25 To r2 Step .1
        cc = cc - .25
        Circle (x2, y2), S, _RGB32(cc, 100 + cc, cc)
    Next S
    cc = 200
    For S = .25 To r3 Step .1
        cc = cc - .25
        Circle (x3, y3), S, _RGB32(100 + cc, cc, cc)
    Next S
    cc = 200
    Line (400, 200)-(x, y), _RGB32(255, 255, 255)
    Line (400, 200)-(x2, y2), _RGB32(255, 255, 255)
    Line (400, 200)-(x3, y3), _RGB32(255, 255, 255)
    x4 = (Sin(t4) * 20) * (_Pi * 2) + 400
    y4 = (Cos(t4) * 10) * (_Pi / 2) + 400
    r4 = (Cos(t4) * 180) / _Pi / 1.5 + 50
    t4 = t4 + (.25 + w / 10)
    x5 = (Sin(t5) * 20) * (_Pi * 2) + 400
    y5 = (Cos(t5) * 10) * (_Pi / 2) + 400
    r5 = (Cos(t5) * 180) / _Pi / 1.5 + 50
    t5 = t5 + (.25 + w / 10)
    x6 = (Sin(t6) * 20) * (_Pi * 2) + 400
    y6 = (Cos(t6) * 10) * (_Pi / 2) + 400
    r6 = (Cos(t6) * 180) / _Pi / 1.5 + 50
    t6 = t6 + (.25 + w / 10)
    For S = .25 To r4 Step .1
        cc4 = cc4 - .25
        Circle (x4, y4), S, _RGB32(cc4, cc4, 100 + cc4)
    Next S
    cc4 = 200
    For S = .25 To r5 Step .1
        cc4 = cc4 - .25
        Circle (x5, y5), S, _RGB32(cc4, 100 + cc4, cc4)
    Next S
    cc4 = 200
    For S = .25 To r6 Step .1
        cc4 = cc4 - .25
        Circle (x6, y6), S, _RGB32(100 + cc4, cc4, cc4)
    Next S
    cc4 = 200
    Line (400, 400)-(x4, y4), _RGB32(255, 255, 255)
    Line (400, 400)-(x5, y5), _RGB32(255, 255, 255)
    Line (400, 400)-(x6, y6), _RGB32(255, 255, 255)
    cc2 = 100
    For sz = .1 To 100 Step .25
        cc2 = cc2 - .25
        Circle (400, 550), sz, _RGB32(100 + cc2, 100 + cc2, cc2), , , .5
    Next sz
    Line (400, 200)-(400, 550), _RGB32(255, 255, 255)
    _Display
    Cls
Loop Until InKey$ = Chr$(27)

Print this item

  mem arrays
Posted by: James D Jarvis - 08-23-2022, 04:45 AM - Forum: Works in Progress - Replies (6)

Other folks using mem and posting about it got me reading the documentation on the _mem commands and I realized it
was a possible solution to a limitation in QB.

I've always wanted to use arrays inside a programmer defined record type. The functions and subs here are an attempt to do so. Currently only supports one dimensional arrays of 2 byte integers.

Code: (Select All)
'mem array functions and subs
Type rectype
    array As _MEM 'this could of course be just one of many entries inside a larger record but this demo code is cleaner with the array alone here
End Type

Dim rec As rectype
Dim r2 As rectype
rec.array = _MemNew(20) 'make a 20 byte mem block to hold an intger array with 10 elements
r2.array = _MemNew(20)
Print "I've always wanted to uses arrays inside record types but that isn't a standard option"
Print "the functions and subs this program uses are made to handle arrays inside such records"
'I chose to do this without creating seperate reference arrays  to establish the arrays as all the routines...
' required to access the arrays don't have to ever look at a seperately defined array
Print
Print "Made 2 integer arays"
Print "Offset", "Size"
Print rec.array.OFFSET, rec.array.SIZE, "Rec"
Print r2.array.OFFSET, r2.array.SIZE, "R2"
Print
'build 2 integer arrays
For x = 1 To 10
    xx% = Int(x * 2)
    x2% = Int(x)
    miput_array xx%, rec.array, x
    miput_array x2%, r2.array, x
Next x
Print "Here are their values"
'manually read the arrays rec.array and r2.array  and print the values
For x = 1 To 10
    n = Int(miget(rec.array, x))
    m = Int(miget(r2.array, x))
    Print n, m
Next
Input "press enter to continue", kk$
'directly setting the first elelemnt in array in r2 to the vale 123
Print "Changed the 1st vlaue of the array r2"
xx% = 123
_MemPut r2.array, r2.array.OFFSET, xx%
'trying out iget function
Print iget(r2, 1)
'trying out        miget function
Print miget(r2.array, 1)
Print
print_iarray r2.array, 1, 10

Input "press enter to continue", kk$
Print
Print "Appending the array at r2 to have 2 more elements"

mem_iappend r2.array, 2
s = iarray_len(r2.array)
For x = 1 To s
    Print miget(r2.array, x);
Next x
Print "array length "; iarray_len(r2.array)
Print "let's fill elements 11 and 12..."
x2% = 11
miput_array x2%, r2.array, 11
x2% = 12
miput_array x2%, r2.array, 12
print_iarray r2.array, 1, s

Print: Print

Print "taking these values"
print_iarray rec.array, 1, 6
Print "and replacing elements 4 to 9 in the last array."
quick_iacopy rec.array, r2.array, 1, 6, 4
print_iarray r2.array, 1, 12


'cleaning up
_MemFree rec.array
_MemFree r2.array

'================================================================================================
'functions and subs to handle arrays inside a memory block
'
'currently only supports 2 byte intgers
'================================================================================================
Sub quick_iacopy (ra As _MEM, rb As _MEM, a1 As Integer, a2 As Integer, b As Integer)
    'take elements a1 to a2 form integer arrai ra and repalce in integer array rb starting at element b
    _MemCopy ra, ra.OFFSET + (a1 - 1) * 2, (a2 + 1 - a1) * 2 To rb, rb.OFFSET + (b - 1) * 2
End Sub

Sub print_iarray (r As _MEM, x1, x2)
    'print elements x1 to x2 in an integer array
    If x1 < x2 Then 'print order is lower element # to higher element #
        For n = x1 To x2
            x = _MemGet(r, r.OFFSET + (n - 1) * 2, Integer)
            Print x;
        Next
        Print
    End If
    If x1 > x2 Then 'print order is higher elelemnt # to lower element #
        For n = x1 To x2 Step -1
            x = _MemGet(r, r.OFFSET + (n - 1) * 2, Integer)
            Print x;
        Next
        Print
    End If
End Sub

Sub miput_array (n As Integer, r As _MEM, e)
    'this puts a 2 byte integer into the array r at element e
    If e > 0 And e <= r.SIZE / 2 Then 'if element is outside array size program will not check incorrect offset but will still return a 0
        _MemPut r, r.OFFSET + ((e - 1) * 2), n
    End If
End Sub

Function iget (r As rectype, e)
    'get elelent e out of the array in the record    ... probably retirng this function as it isn't as robust as miget
    iget = _MemGet(r.array, r.array.OFFSET + (e - 1) * 2, Integer)
End Function

Function miget (r As _MEM, e)
    'mem integer get,  grab element out of the array at r
    miget = _MemGet(r, r.OFFSET + (e - 1) * 2, Integer)
End Function

Sub mem_iappend (r As _MEM, n)
    'add n elements to an integer array
    SA$ = Str$(r.SIZE)
    s = Val(_Trim$(SA$))
    Dim temp As _MEM
    temp = _MemNew(s)
    _MemCopy r, r.OFFSET, r.SIZE To temp, temp.OFFSET
    _MemFree r 'now ths is strange, if you don't do this the address of the offset will change after the next command, not a big deal but a curisotiy
    r = _MemNew(s + n * 2)
    _MemCopy temp, temp.OFFSET, temp.SIZE To r, r.OFFSET
    _MemFree temp
End Sub

Function iarray_len (r As _MEM)
    ll% = Int(Val(_Trim$(Str$(r.SIZE))) / 2)
    iarray_len = ll%
End Function

Print this item

  Questions about _MEMs and UDT's
Posted by: justsomeguy - 08-22-2022, 09:04 PM - Forum: General Discussion - Replies (1)

Is it possible to pass _MEM handles to Functions/Subs without having to make it global?

Is there a way to normalize the behavior of strings in UDT's? Uninitialized strings in UDT's are filled with CHR$(0), and initialized strings are padded with spaces at the end. Trying to determine the actual string length is difficult, because I can't tell if the spaces are intentional or not.

Are variable length strings in UDT allowed? I though that they weren't. But it seems if you use the right syntax they are allowed, but I found that I can get some strange behaviors if I use them. (Not demonstrated in code.)

I've demonstrated my questions in the following code.

Code: (Select All)
TYPE tTEST
  st AS STRING * 12
END TYPE

TYPE tTESTBUG
  AS STRING st
END TYPE

DIM AS tTEST test
DIM AS tTESTBUG testbug

PRINT "Uninitialized String."
prntSTR test

PRINT "Initialized String."
test.st = "Hello"
prntSTR test

PRINT "Variable length String in UDT? "
PRINT "Uninitiated String."
prntSTRBug testbug

PRINT "Initialized String."
testbug.st = "Hello"
prntSTRBug testbug


SUB prntSTR (test AS tTEST)
  DIM i AS LONG
  FOR i = 1 TO LEN(test.st)
    PRINT ASC(MID$(test.st, i, 1)); " ";
  NEXT
  PRINT
END SUB

SUB prntSTRBug (test AS tTESTBUG)
  DIM i AS LONG
  FOR i = 1 TO LEN(test.st)
    PRINT ASC(MID$(test.st, i, 1)); " ";
  NEXT
  PRINT
END SUB

Print this item