Author Topic: MasmBasic  (Read 345801 times)

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #510 on: May 04, 2020, 07:45:03 AM »
Not yet. I guess it's useless anyways because I have only one voice installed. Extra voices cost real money.

There is a demo here. Try with the text below - amazing!

There are many reasons why experienced programmers choose to write assembler code, performance issues where speed matters, the architectural freedom to lay out code in any way you like, the capacity to do things that cannot be done in many compilers but the main reason is simply because you can. Many conjure up the image of cobbling together a few DOS interrupts in unintelligible notation to prop up the shortcomings of compilers yet a modern assembler like MASM has the range of a high level language and can be written that way for high level code while retaining all of its power at the lowest level.

With the introduction of the 32 bit Windows API functions, MASM had access at the same functions that compilers had from the operating system but without the clutter and assumption of many of the compilers available. When you write Windows API code in MASM you get perfectly clear minimal precision code that leverages the full power of the Windows operating system and you get it at the code size you write, not with a pile of unwanted extras dumped into your executable by a compiler.

MASM has never been for the faint of heart, it is an uncompromised tool that has never been softened into a user friendly toy and it required the development of expertise to use correctly but for the programmer who already has experience in low level C and similar code, MASM offers power and flexibility that the best of compilers cannot deliver and contrary to popular opinion it can be developed and written at about the same development time as C code.

Siekmanski

  • Member
  • *****
  • Posts: 2365
Re: MasmBasic
« Reply #511 on: May 04, 2020, 08:40:03 AM »
I heard the text from your example.  :cool:
Copied it in the link you posted, there are some High Quality ones.

I have 2 amazingly High Quality SAPI5 Dutch female voices. (paid 200 euros for the 2 voices, today you can get 1 for 40 euros. )
Unfortunately they will only install on Windows 32bit.  :sad:
Creative coders use backward thinking techniques as a strategy.

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #512 on: May 04, 2020, 09:15:37 AM »
I have downloaded the SDK from http://download.microsoft.com/download/B/4/3/B4314928-7B71-4336-9DE7-6FA4CF00B7B3/SpeechSDK51.exe

Mary & Mike don't work, and "Sample TTS voice" works but says most of the time "bla" (really :tongue:)

Siekmanski

  • Member
  • *****
  • Posts: 2365
Creative coders use backward thinking techniques as a strategy.

TimoVJL

  • Member
  • ****
  • Posts: 723
Re: MasmBasic
« Reply #514 on: May 05, 2020, 01:07:50 AM »
A test program for SAPI 5.x
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <sapi.h>

#pragma comment(lib, "ole32.lib")

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
ISpVoice * pVoice = NULL;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_ALL, &IID_ISpVoice, (void **)&pVoice);
if (SUCCEEDED(hr))
{
hr = pVoice->lpVtbl->Speak(pVoice, L"<voice optional='Gender=Male;'>Hello world", 0, NULL);
//hr = pVoice->lpVtbl->Speak(pVoice, L"<voice required='Gender = Male;'>Hello world", 0, NULL);
//if (hr) hr = pVoice->lpVtbl->Speak(pVoice, L"<voice required='Gender = Female;'>Hello world", 0, NULL);
pVoice->lpVtbl->Release(pVoice);
pVoice = NULL;
}
CoUninitialize();
return 0;
}
« Last Edit: May 05, 2020, 04:36:45 AM by TimoVJL »
May the source be with you

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #515 on: May 05, 2020, 07:52:09 AM »
Very interesting, Timo - I didn't know that you can specify options with XML tags:
Code: [Select]
hr = pVoice->lpVtbl->Speak(pVoice, L"<voice optional='Gender=Male;'>Hello world, I am a man", 0, NULL);
if (1)
hr = pVoice->lpVtbl->Speak(pVoice, L"<voice required='Gender=Female;'>Hello world, I am a woman", 0, NULL);
With this modification, I hear both strings spoken by the same female voice when built as X64, but only "I am a woman" when built as x86  :sad:

With MasmBasic:

Say wChr$("<voice optional='Gender=lgbt;'>Good morning")


For Gender=, everything works fine except Gender=male, which is mute :rolleyes:

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #516 on: July 29, 2020, 07:40:14 PM »
Update 28 July 2020 (in response to fast median thread and timings)

include \masm32\MasmBasic\MasmBasic.inc
  Init
  Dim MyArray() As REAL4        ; can be DWORD, REAL4 or REAL8
  For_ ecx=0 To 99
        Rand(-888.8, 999.9, MyArray(ecx))       ; put random numbers into the array
  Next
  PrintLine Str$("The elements:\t%i", MyArray(?))
  PrintLine Str$("The columns:\t%i", MyArray(?cols))    ; will return 0: this array is one-dimensional
  PrintLine Str$("The minimum:\t%f", MyArray(?min)v)    ; the functions marked with v return the
  PrintLine Str$("The maximum:\t%9f", MyArray(?max)v)   ; value in ST(0); the v tells Str$() to discard
  PrintLine Str$("The median:\t%f", MyArray(?median)v; ST(0) with fstp st after printing
  PrintLine Str$("The mean:\t%9f", MyArray(?mean)v)     ; ?average does the same as ?mean
  PrintLine Str$("The sum: \t%9f", MyArray(?sum)v)      ; sum of all elements
EndOfCode


Code: [Select]
The elements:   100
The columns:    0
The minimum:    -884.9537
The maximum:    994.308716
The median:     -8.574001
The mean:       35.9553806
The sum:        3595.53806
« Last Edit: July 29, 2020, 09:56:44 PM by jj2007 »

Siekmanski

  • Member
  • *****
  • Posts: 2365
Re: MasmBasic
« Reply #517 on: July 29, 2020, 09:12:59 PM »
Cool, all in one.  :cool:
Creative coders use backward thinking techniques as a strategy.

guga

  • Member
  • *****
  • Posts: 1357
  • Assembly is a state of art.
    • RosAsm
Re: MasmBasic
« Reply #518 on: July 30, 2020, 06:17:44 AM »
Great work, JJ

One question about the median function.

Here
Code: [Select]
  fld st
  faddp st(2), st
  fsub arrInf.yMin ; make positive
  fmul arrInf.yRange ; normalise 0...99999
  ; fadd FP4(0.45)
  fistp arrInf.yIndex ; we need a
  mov eax, arrInf.yIndex ; reg32
  inc dword ptr [edi+4*eax] ; Populate the Median buffer with the values as index numbers and keep track for duplicates in one go
  dec ecx
  jns aiPop ; 0 is still ok

the size of the Table (MedBuffer) used in edi must be the double when we are dealing with negative values, right ?

I mean, say i have limits from -255 to 255, then the total size of the table should be (256*4*2) ?

Also, since it will be subtracting the negative values to set onto the proper address of the table, should it calculate the median and preserve the sign in case the resultant median is also negative ?

I previously normalized the inputed data to -1 to 1, so i divided each value with 255. On your version, at that routine, i made the following port:

Code: [Select]
; [Med_MinVal_Normalized: R$ -1.0] = < --- The minimum value as set in arrInf.yMin already normalized

    Do
        fld F$esi | fsub R$Med_MinVal_Normalized | fmul R$Float255 | fistp D@Index | mov eax D@Index ; Multiplied the input with 255 to it points to the proper address on the table.
        inc D$edi+eax*4   ; Populate the Median buffer with the values as index numbers
        add esi ebx       ; and keep track for duplicates in one go. And skip positions if needed
    Repeat_Until_Zero ecx

Is this correct ? Will it result a negative median (thus, preserving the sign) if the median is, in fact, negative ?
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #519 on: July 30, 2020, 10:39:15 AM »
Hi Guga,
In the example above the range of values is determined by the Rand(-888.8, 999.9, destination). The normalisation takes care of negative numbers. In fact, the median for this dataset is slightly negative.
Code: [Select]
The minimum:    -884.9537
The maximum:    994.308716
The median:     -8.574001
The mean:       35.9553806

guga

  • Member
  • *****
  • Posts: 1357
  • Assembly is a state of art.
    • RosAsm
Re: MasmBasic
« Reply #520 on: July 30, 2020, 12:11:06 PM »
Hi JJ, ok, but how the normalization works ? The math operation, i mean.

I saw it takes the subtraction of the Maxvalue to the MinValue, but it will divide by what ?

Fraction = (Max-Min)/ WhatData ?

What Data is suppose to be divided with ? If we have negative numbers, it means we have double the amount of values, right ? ex, if the limits to be settled are -255 to 255, it means we have, in fact a limit of 255*2 data to load. So, if our Minimum value found is, let´s say -200 and Max is 185, then to apply the normalization, is correct to do this ?

Fraction = (185-(-200))(2*255) = (185+200)/510 = 385/510 = 0.754901961

So, our Fraction (arrInf.yRange) would be 0.754901961, right ?

And to recover the proper median at the end of the function, we do this ?

New Value = ValueFound/Fraction - Minimum Value ? = ValueFound/0.75490191 - (-200) ?


Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #521 on: July 30, 2020, 06:35:55 PM »
Hi JJ, ok, but how the normalization works ? The math operation, i mean.

Search for arrInf.yRange - it should be self-explanatory :cool:

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #522 on: October 03, 2020, 09:29:44 AM »
New version online

There are numerous little improvements under the hood. One new feature: RichMasm knows a new option called "Close" (see the Capitals of Europe thread for an example).

Code: [Select]
OPT_Close Capitals of Europe ; close the window before building
When testing a Windows program, I often forget to close it before hitting F6 (the build all key). Inevitably, the linker chokes because the exe is still running. Now with OPT_Close <the window title> RichMasm sends a WM_CLOSE message to the running exe, and it closes (unless there are data to be saved, of course). Problem solved :tongue:

Another new feature: the canvas control (for plots, images and maps, see e.g. GuiImage) has now a right-click context menu for saving its content to the clipboard or to a file. It can also be zoomed to fill the entire client area.

The one-line If_ accepts now also Exist(), FileOpen$() etc args:
Code: [Select]
include \masm32\MasmBasic\MasmBasic.inc
  Init
  If_ Exist("*.bmp") Then PrintLine "yeah, ", Exist$, " exists"
  If_ not Exist("no.bmp") Then Print "Nope, it does not exist"
EndOfCode

Btw did you know the difference between these two?
a) ; int 3
b) int 3

With a), hitting F6 builds and launches the executable
With b), hitting F6 builds and launches \Masm32\OllyDbg\ollydbg.exe <executable path>

Greetings from a lazy programmer :tongue:

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #523 on: October 06, 2020, 09:22:30 PM »
New version online

Here is an attempt to use an I/O library to communicate with ports, inspired by this FreeBasic thread:

include \masm32\MasmBasic\MasmBasic.inc         ; download
  Init
  Cls
  if 0
        Dll "InpOut32"          ; WikiDll; first three functions
  else
        Dll "DlPortIO"          ; Scientific Software Tools at WikiDll ; next four
  endif
  Declare void Out32, 2         ; ushort port, data
  Declare void Inp32, 2         ; ushort port, data
  Declare IsInpOutDriverOpen    ; no args
  Declare DlPortReadPortUshort, 1       ; ushort port
  Declare DlPortReadPortUlong, 1       ; int port
  Declare DlPortWritePortUshort, 2     ; int port, data
  Declare DlPortWritePortUlong, 2      ; int port, data
  PrintLine Str$("Out32: %i", Out32(?))        ; prints the address or zero if the function was not found
  If_ IsInpOutDriverOpen(?) Then <Print Str$("driver open: %i\n", IsInpOutDriverOpen())>        ; crashes
  If_ Out32(?) Then <Out32(111h, 222h)>        ; crashes
  If_ DlPortReadPortUshort(?) Then <Print Str$("read port: %i\n", DlPortReadPortUshort(99))> ; error message
  PrintLine "done"
EndOfCode


The DLLs are available at various places, see links above, but it is unclear how they actually work. Inp32 and Out32 are actually straightforward, under the hood you see in al, dx and out dx, al, but the rest is badly documented.

What's new in MasmBasic then?
- SomeFunction(?) checks if the function has been loaded - see IsInpOutDriverOpen(?) above
- in console mode, you get feedback on Declare:
Code: [Select]
not found (line 9):     Out32
not found (line 10):    Inp32
not found (line 11):    IsInpOutDriverOpen

Unrelated: $Data accepts now empty strings. This was inspired by Guga's Resource String Table thread. If, for example, you copy \Masm32\include\masm32rt.inc into a source (to display the strings, whatever), there are some empty strings, and they used to choke with $Data. This little problem has been solved*)

In case you want a huge string table copied from a text file:
- File/New/Masm source: pick the Console example
- between the include line and Init, paste the lines from the text file
- select the whole block
- press Alt R
- insert $Data ]#[ into the replace edit control, hit Return and confirm
- insert these three lines under Init:
Code: [Select]
  Read my$()
  For_ ecx=0 To eax-1
PrintLine my$(ecx)
  Next

*) at least for UAsm and AsmC - M$ MASM misbehaves on this one, and for ML there is no workaround other than deleting the offending empty line; otherwise, the whole MasmBasic library is fully compatible with ML versions 6.15 ... 14 or so, but attention, some recent ML versions have ugly bugs. I strongly recommend to use UAsm.

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 11550
  • Assembler is fun ;-)
    • MasmBasic
Re: MasmBasic
« Reply #524 on: October 12, 2020, 10:34:27 AM »
Version 12 October is online

- version 3 of Capitals of Europe will build with the latest MasmBasic package (maps with flicker-free Unicode tooltips)
- new macro LineNumber(buffer, search$):

Code: [Select]
include \masm32\MasmBasic\MasmBasic.inc
Init
Print Str$("The string 'Duplicate' is in line %i of Windows.inc", LineNumber(FileRead$("\Masm32\include\Windows.inc"), "Duplicate")+1)
EndOfCode

Output:
Code: [Select]
The string 'Duplicate' is in line 26900 of Windows.inc
Optional 3rd argument: mode as for Instr_(), i.e. 1=case-insensitive, 2=first char of match case-insensitive, 4=full word...
Optional 4th argument: line delimiter char, e.g. 13 (default is 10=linefeed)

LineNumber() is not particularly fast, but it returns the #lines of Duplicate in Windows.inc in under 3ms on my trusty old Core i5 - reading the file included :cool: