Results 1 to 20 of 20

Thread: [RESOLVED] QBasic/Qb45 high precision timing->

Hybrid View

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Resolved [RESOLVED] QBasic/Qb45 high precision timing->

    Whenever I needed a delay in my QBasic/QB45 program I would use a simple delay based on the TIMER function:

    Code:
    DEFINT A-Z
    CLS
     Delay! = .25
     DO
      StartTime! = TIMER
      DO WHILE TIMER < StartTime! + Delay! OR TIMER < StartTime!
       'Put code that doesn't need to be timed here.
      LOOP
      'Put code that needs to be timed here.
      PRINT "*";
     LOOP
    However sometimes I would want to use more precise timing but could never figure out a decent way of implementing it. After some searching online I found it was very hard to find anything about this subject for QBasic. What I found usually was in some other language using some internal high-precision Delay method (Turbo Basic and Turbo C++ for example.) or some highly technical info about the 8253/8253 PIT chip. The closest I have found to what I need is at https://www.franksteinberg.de/pbeisp.htm in a file called "Timing.zip". Unfortunately most of the commenting and documentation is in German and what I have found in English are long-winded technical documents.

    My question is: could someone help me narrow down all this information to something straightforward that does pretty much the same thing as in my TIMER example, but with greater precision?

    Yes, I know QBasic/QB45 might be too slow to go into the millisecond range unless the CPU is fast enough without resorting to assembly code, but I would prefer to avoid assembly language if possible. While I do understand assembly language somewhat, any attempt at using it in combination with QBasic/QB45 by me resulted in just freezing the system. There is something about CALL ABSOLUTE I never quite got.

  2. #2
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    Are you running the original QBasic in an environment like DOSBox or FreeDOS. If that's that case, this might be a very tall order.

    You could try something like QB64 instead which is something like 99% compatible with the original QuickBasic. Since that version is actually built using modern techniques, it might be possible to expose the Win32 API to it through a library or some other method and then you can use Windows Performance Counters for high precision timing.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    Yes, it might not be easy but from what I can tell it should be possible to do it in original QBasic. Part of the reason I am trying it is because I want to know how old DOS games managed precision timing. If QBasic isn’t suitable, a C (fit for DOS) example will do as well.

  4. #4
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    I seriously doubt DOS games used high precision timing like we have today. But I don't know enough about this to say that for a fact. Nonetheless, if there was high precision timers that QB couldn't access, then assembly/C would be your own hope. You'd have to write it in ASM/C, then compile it. The compiler would produce object files which you can then input into the QB compiler's linking process and your QB program would have access to the functions. My memory of all this is very vague and some of this was way over my head at the time so I can't really give you any specifics.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    As far as I know there wasn’t high precision timing exactly like we have today, but I know it was done some how. Think about it, a lot of older games have things going on at CPU independent speeds with intervals in between frames that must be less than 54 milliseconds (one 18th of a second). That’s the best QBasic’s native functions can do. Turbo Basic for DOS has an internal Delay statement that can do millisecond precision. Also DOS games output audio that must be precisely timed.

    Well, does anyone reading this know how to do it in assembly language? Or C?

  6. #6
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    Hmm....Lets try this a different way. What is it that you're trying to do that you can't seem to do with the normal system timer?
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  7. #7

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    As far as I know the normal system timer can't handle intervals smaller than one 18th of a second, can it?

  8. #8
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    Quote Originally Posted by Peter Swinkels View Post
    As far as I know the normal system timer can't handle intervals smaller than one 18th of a second, can it?
    I've always assumed it to be 50 ms, a habit I developed from my VB6 days. In truth I'm not sure what the true resolution is or even if it's the same across all systems. It even gets more complicated as there might actually be different mechanisms for timing in a computer's hardware. I'm far from an expert in this. I've relied on timers a lot in my life and still do but I have never had a reason to want crazy accurate resolutions. This is why I'm curious as to exactly why you need this. Give this a read. Maybe it would shed some light on this for you.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  9. #9

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    Quote Originally Posted by Niya View Post
    I've always assumed it to be 50 ms, a habit I developed from my VB6 days. In truth I'm not sure what the true resolution is or even if it's the same across all systems. It even gets more complicated as there might actually be different mechanisms for timing in a computer's hardware. I'm far from an expert in this. I've relied on timers a lot in my life and still do but I have never had a reason to want crazy accurate resolutions. This is why I'm curious as to exactly why you need this. Give this a read. Maybe it would shed some light on this for you.
    No, it's exactly 1000 / 18. I don't need it, but I am curious as to how it was during the DOS days, if not using QBasic, then something else. I don't think what I am asking for is crazy accurate. Look at some older DOS stuff, the timing in some of that software had to be more precise than 50ms.

  10. #10
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    At this point I have to wonder, are we 100% sure that these DOS programs use timers more accurate than what was available to QBasic? I don't mean just a feeling or intuition but 100% certain of this.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  11. #11

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    https://youtu.be/nRMrzqKoGpY Does this game look like it's running at 54ms intervals to you? It's timed alright, I know for a fact it runs at the same speed on anything from 4.77mhz to at least 600mhz.

  12. #12
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: QBasic/Qb45 high precision timing->

    Well, most DOS games weren't written in QBASIC.
    But, in any case, even with games that were written with QB45, that were compiled, you could do a simple call to get the Vertical Retrace line count of the graphic card.

    The timing of your game would be based on the refresh rate of your monitor. A VGA monitor in the lower resolution that most of the games were written in would support multiple screens worth of memory, so you could either double buffer by using the video memory and switching pages during the vertical refresh period, or if you wanted to use a higher resolution mode where you had less than two screens worth of memory available, you could write to a memory buffer and then copy the buffer to the video memory during the retrace period.

    Since your program would loop and check for the video scan line index to see when the vertical retrace period would occur, some program would even take advantage and not wait for the vertical retrace, but would, for example, start updating the upper portion of the screen once the scan line sweep had passed a certain point. For instance, say you were running the standard 640x480 graphics mode, you could start updating the upper 240 lines while the screen was in the process of refreshing the lower 240 lines of the screen.

    Of course, drawing to a memory buffer meant you wouldn't be using the built in graphic commands of the QB45 language, but would have your own library of drawing primitives that would write to the memory buffer, i.e. instead of using the Line command to draw a line, you would have a function that implemented Bresenham's line algorithm to draw a "line" into a "rectangular" byte array that represented your video memory.
    Last edited by passel; Aug 9th, 2021 at 05:35 AM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  13. #13

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    @passel:

    I made a simple bouncing ball program using vertical retracing as a timing method:

    Code:
    DEFINT A-Z
    SCREEN 12: CLS
    x = 320
    y = 240
    DirectionX = 1
    DirectionY = 1
    DO
     CIRCLE (x, y), 10, 0
     DO
      IF INKEY$ = CHR$(27) THEN END
     LOOP WHILE (INP(&H3DA) XOR &H8) AND &H8 = &H0 'This part does the same as "WAIT &H3DA, &H8, &H8".
     IF x <= 0 OR x >= 639 THEN DirectionX = -DirectionX
     IF y <= 0 OR y >= 479 THEN DirectionY = -DirectionY
     x = x + DirectionX
     y = y + DirectionY
     CIRCLE (x, y), 10, 2
    LOOP
    Whether or not I actually use the WAIT statement I can tell the program's speed increases as I increase the number of cycles in DOSBox. What am I doing wrong?

  14. #14
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: QBasic/Qb45 high precision timing->

    Well, I wonder if testing the &H3DA port is actually valid under DOSBox. Perhaps DOSBox does emulate the VGA correctly to have the games work correctly.

    Assuming that is the case, did you get the "equivalent" code for "WAIT" from some source.
    It doesn't look like the code should work.

    WAIT &H3DA, &H8 should just AND 8 to the port, so will either return True (-1 long) if the result is 8, or 0 otherwise.

    Your doing an XOR with 8 will toggle the bit, so if it is a 1, the result will be 0, and then if you AND 0 with 8 it will still be 0.
    This seems to be the opposite of what you want.

    I would think all you would need is:

    LOOP WHILE (INP(&H3DA) AND &H8)
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  15. #15
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: QBasic/Qb45 high precision timing->

    Looking at the code a bit more, I think you actually need a two step check to sync your loop to the vsync.

    You are checking the state of bit 3 (mask 8), but the bit will be 0 while not in the vertical sync period, and it will be 1 while in the vertical sync period, but the point is the vertical sync period is a "period" of time. If you want to sync to the sync, then you want to exit the sync loop on a transition (0 to 1, or 1 to 0), not on the state of the bit.

    Something along the lines of:
    Code:
      DO
        IF INKEY$ = CHR$(27) THEN END
      LOOP WHILE (INP(&H3DA) AND &H8) = &H0 
      DO
        IF INKEY$ = CHR$(27) THEN END
      LOOP WHILE (INP(&H3DA) AND &H8) = &H8
    The above will exit the vsync on the 1 to 0 transition.
    If the bit is 0, then it will wait in the first loop until it goes to 1, then it will wait in the second loop until it goes back to 0, and then you code will run one cycle, and then come back and wait for the next 1 to 0 transition.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  16. #16

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    @Passel: I changed the looping condition as you suggested, it still runs at CPU dependent speed. I would have to ask at the DOSBox forums whether DOSBox supports vertical retrace.

  17. #17
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: QBasic/Qb45 high precision timing->

    Quote Originally Posted by Peter Swinkels View Post
    @Passel: I changed the looping condition as you suggested, it still runs at CPU dependent speed. I would have to ask at the DOSBox forums whether DOSBox supports vertical retrace.
    Wait....Before you do that, run a game called Prince of Persia on DOSBox and change the CPU speed and see if the game runs faster or slower. Prince of Persia was the first DOS game I had ever seen that ran at the same speed regardless of how fast or slow the processor was. Even Alley Cat ran at different speeds depending on processors. I played both games extensively in my childhood. Prince of Persia ALWAYS ran at the same speed. If it can do that in DOSBox, then what you're asking is possible. You just have to figure out how they did it.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  18. #18

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    @Passel:

    The verticle retrace works now:

    Code:
    DEFINT A-Z
    SCREEN 12: CLS
    x = 320
    y = 240
    DirectionX = 1
    DirectionY = 1
    DO
     DO
      IF INKEY$ = CHR$(27) THEN END
     LOOP WHILE (INP(&H3DA) AND &H8) = &H0
    
     DO
      IF INKEY$ = CHR$(27) THEN END
     LOOP WHILE (INP(&H3DA) AND &H8) = &H8
    
     CIRCLE (x, y), 10, 0
    
     IF x <= 0 OR x >= 639 THEN DirectionX = -DirectionX
     IF y <= 0 OR y >= 479 THEN DirectionY = -DirectionY
     x = x + DirectionX
     y = y + DirectionY
     CIRCLE (x, y), 10, 2
    LOOP
    It's running at one 60th of second, correct? Unfortunately that's not much better than using the TIMER function. I still appreciate the help though. :-)

    At the DOSBox forums (were I asked the same question) they suggested using INT 0x15.

  19. #19

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->

    I may have found an acceptable solution:

    Code:
    DEFINT A-Z
             Delay$ = CHR$(&HB4) + CHR$(&H86)   'MOV AH, 0x86
    Delay$ = Delay$ + CHR$(&HB9) + MKI$(&H0)    'MOV CX, HighByte
    Delay$ = Delay$ + CHR$(&HBA) + MKI$(&HFA)   'MOV DX, LowByte
    Delay$ = Delay$ + CHR$(&HCD) + CHR$(&H15)   'INT 0x15
    Delay$ = Delay$ + CHR$(&HCB)                'RETF
    
    DEF SEG = VARSEG(Delay$)
    
    SCREEN 12: CLS
    
    x = 320
    y = 240
    DirectionX = 1
    DirectionY = 1
    DO UNTIL INKEY$ = CHR$(27)
     CIRCLE (x, y), 10, 0
     IF x <= 0 OR x >= 639 THEN DirectionX = -DirectionX
     IF y <= 0 OR y >= 479 THEN DirectionY = -DirectionY
     x = x + DirectionX
     y = y + DirectionY
     CIRCLE (x, y), 10, 2
     CALL ABSOLUTE(SADD(Delay$))
    LOOP
    Although this freezes the program for brief time, unlike what I initially was looking for this might do. I would have to try writing an actual game with it or modify something I already wrote.

  20. #20

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,807

    Re: QBasic/Qb45 high precision timing->


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width