{--------------------------------------------------------}
{
{    Interface sonora para o mixer de áudio do Windows
{
{    Por José Antonio Borges
{
{    Em 29/05/98
{
{--------------------------------------------------------}

{$M 16384, 8192}
program mixerVox;
uses winprocs, wintypes, dvcrt, dvwin, dvexec, dvmacro, strings, win31;

const
    versao = '1.0';

type
    TCanal = record
        nomeCanal: string[20];
        aceitaBalanco: boolean;
        balanco: longint;
        aceitaVolume: boolean;
        volume: longint;
        aceitaHabilit: boolean;
        habilit: boolean;
        aceitaGraves: boolean;
        graves: byte;
        aceitaAgudos: boolean;
        agudos: byte;
        aceitaAvancado: boolean;
    end;

var
    janAnterior, minhaJan, janMixer: hwnd;
    ncanais: integer;
    canal: array [1..20] of TCanal;
    modoAtual: integer;
    ligaEcoMic: boolean;

procedure mensagem (nomeArq: string; nlf: integer);
var i: integer;
    s: string;
begin
    if nomeArq = 'MXINIC' then
        s := 'Programa de Ajuste de Volume'
    else
    if nomeArq = 'MXFIM' then
        s := 'Mixer fechado'
    else
    if nomeArq = 'MXERRPRG' then
        s := 'Erro ao carregar o mixer do Windows'
    else
    if nomeArq = 'MXRECONF' then
        s := 'Reconfigurando todo mixer, espere'
    else
    if nomeArq = 'MXOK' then
        s := 'Ok'
    else
    if nomeArq = 'MXVOLPAD' then
        s := 'Qual o volume padrão de 0 a 100  '
    else
    if nomeArq = 'MXLIGMIC' then
        s := 'Liga eco do microfone ? '
    else
    if nomeArq = 'MXQUALOP' then
        s := 'Qual opção: '
    else
    if nomeArq = 'MXAJUDA' then
        s := 'R - reconfigura tudo,  A - ajustes de áudio,  G - ajustes de gravação'
    else
    if nomeArq = 'MXUSESET' then
        s := 'Use as setas depois enter para selecionar o canal'
    else
    if nomeArq = 'MXULTCAN' then
        s := 'Último canal...'
    else
    if nomeArq = 'MXDESIS' then
        s := 'Desistiu'
    else
    if nomeArq = 'MXERRVAL' then
        s := 'Valor inválido, redigite, ESC desiste'
    else
    if nomeArq = 'MXALTERA' then
        s := 'Alterando canal '
    else
    if nomeArq = 'MXBALANC' then
        s := 'Balanço'
    else
    if nomeArq = 'MXVOLUME' then
        s := 'Volume '
    else
    if nomeArq = 'MXVALATU' then
        s := '  Valor '
    else
    if nomeArq = 'MXNOVVAL' then
        s := '  Qual o novo valor (enter mantém) '
    else
    if nomeArq = 'MXPOSHAB' then
        s := 'Posso habilitar ? '
    else
    if nomeArq = 'MXESTALG' then
        s := 'Está ligado'
    else
    if nomeArq = 'MXESTADL' then
        s := 'Está desligado'
    else
    if nomeArq = 'MXFICALG' then
        s := 'Fica ligado ? '
    else
    if nomeArq = 'MXCMAVAN' then
        s := 'Quer fazer ajustes avançados ? '

    else
        s := '--> Mensagem invalida: ' + nomeArq;

    write (s);
    for i := 1 to nlf do
         writeln;

    if existeArqSom (nomeArq) then
        sintSom (nomearq)
    else
        sintetiza (s);
end;

{---------------------------------------------------------------------}

procedure trocaJan (j: hWnd);
begin
    setActiveWindow (j);
    repeat
        calaboca;
        delay (100);
    until keypressed or (getActiveWindow = j);
    calaboca;
end;

{---------------------------------------------------------------------}

procedure inicializa;
var j: hwnd;
    nome: array [0..144] of char;
    n: integer;
    dir: string;
begin
    screenSize.y := 10;
    janAnterior := getActiveWindow;
    clrscr;
    minhaJan := getActiveWindow;

    dir := sintAmbiente ('MIXERVOX', 'DIRMIXERVOX');
    if dir = '' then
        dir := 'c:\winvox\som\mixervox';
    sintInic (0, dir);

    mensagem ('MXINIC', 0);   {'Mixer Vox - v '}
    writeln (' - v ', versao);
    while sintFalando do;
    while keypressed do readkey;

    if executaProg ('sndvol32', '.', '') <= 32 then
        begin
            mensagem ('MXERRPRG', 1);   {'Erro ao carregar o mixer do Windows'}
            sintFim;
            doneWinCrt;
        end;

    repeat keypressed until getActiveWindow <> minhaJan;
    janMixer := getActiveWindow;
    trocaJan (minhaJan);

    modoAtual := 0;
    ncanais := 0;
    ligaEcoMic := false;
end;

{---------------------------------------------------------------------}

procedure pegaCanaisAtivos;
var j: hwnd;
    classe, nome: array [0..255] of char;
    n: integer;
    s: string;
    place: twindowplacement;

    procedure pegaCanal;
    begin
        ncanais := ncanais + 1;
        with canal [ncanais] do
            begin
                nomeCanal := s;
                j := getWindow (j, GW_HWNDNEXT);  {static balanco}
                j := getWindow (j, GW_HWNDNEXT);  {static volume}

                j := getWindow (j, GW_HWNDNEXT);  {controle de balanco}
                aceitaBalanco := isWindowEnabled (j);
                balanco := sendMessage (j, WM_User, 0, 0);

                j := getWindow (j, GW_HWNDNEXT);  {controle de volume}
                aceitaVolume := isWindowEnabled (j);
                volume := 255 - sendMessage (j, WM_User, 0, 0);

                j := getWindow (j, GW_HWNDNEXT);  {vu meter}

                j := getWindow (j, GW_HWNDNEXT);  {sem audio}
                aceitaHabilit := isWindowEnabled (j);
                getWindowText(j, nome, 80);
                habilit := sendMessage (j, BM_GETSTATE, 0, 0) = 0;
                if copy (strpas (nome), 1, 5) = '&Sele' then
                    habilit := not habilit;

                j := getWindow (j, GW_HWNDNEXT);  {avancado}
                aceitaAvancado := isWindowEnabled (j) and isWindowVisible (j);
            end;

    end;

begin
    trocaJan (janMixer);
    getWindowText (getActiveWindow, nome, 255);

    nCanais := 0;
    j := getWindow (janMixer, GW_CHILD);

    s := '';
    while j <> 0 do
        begin
            getClassName (j, nome, 255);
            s := strPas (nome);
            if s = 'Static' then
                begin
                    getWindowText (j, nome, 255);
                    s := strPas (nome);
                    if (length (s) > 3) then
                        pegaCanal;
                end;

            if j <> 0 then
                j := getWindow (j, GW_HWNDNEXT);
        end;

    trocaJan (minhaJan);
end;

{---------------------------------------------------------------------}

procedure selModo (qualModo: integer);
var nome: array [0..144] of char;
begin
    playInit (300);
    playAltKey ('O', 1);
    playKey ('P', 1);
    delay (200);

    playKey (^i, 1);

    while qualModo <> modoAtual do
        begin
            if qualModo > modoAtual then
                begin
                    playVirtKey (VK_DOWN, false, false, false, 1);
                    modoAtual := modoAtual + 1;
                end
            else
                begin
                    playVirtKey (VK_UP, false, false, false, 1);
                    modoAtual := modoAtual - 1;
                end;
        end;

    playKey (TAB, 1);
    playKey (TAB, 1);
    playKey (ENTER, 1);
    playStart;

    while  playIsActive do
        begin
            calaboca;
            keypressed;
        end;

    delay (500);

    janMixer := getActiveWindow;
end;

{--------------------------------------------------------}

procedure posicCanal (ncanal: integer);
var c: integer;
begin
    if ncanal > 1 then
        begin
            for c := 1 to ncanal-1 do
                with canal[c] do
                    begin
                        if aceitaBalanco  then   keyboardClick (TAB);
                        if aceitaVolume   then   keyboardClick (TAB);
                        if aceitaHabilit  then   keyboardClick (TAB);
                        if aceitaAvancado then   keyboardClick (TAB);
                    end;
        end;
end;

{---------------------------------------------------------------------}

procedure acertaCanal (modo, ncanal, pan, vol, habil: integer);
var c, i: integer;
begin
    trocaJan (janMixer);
    selModo (modo);

    pan := trunc ((pan / 100) * 63);
    vol := trunc ((vol / 100) * 255);

    posicCanal (ncanal);

    with canal [ncanal] do
        begin
            delay (200);
            if aceitaBalanco and (pan >= 0) then
                 begin
                     playInit (300);
                     for i := 1 to 6 do
                         playVirtKey (VK_PRIOR, false, false, false, 1);
                     for i := 1 to pan do
                         playVirtKey (VK_RIGHT, false, false, false, 1);
                     playKey (TAB, 1);
                     playStart;
                     while playIsActive do
                         begin
                              calaboca;
                              keypressed;
                         end;
                 end;

            if aceitaVolume and (volume >= 0) then
                 begin
                     playInit (300);
                     for i := 1 to 6 do
                         playVirtKey (VK_NEXT, false, false, false, 1);
                     for i := 1 to vol div 51 do
                         playVirtKey (VK_PRIOR, false, false, false, 1);
                     for i := 1 to vol mod 51 do
                         playVirtKey (VK_UP, false, false, false, 1);
                     playKey (TAB, 1);
                     playStart;
                     while  playIsActive do
                         begin
                             calaboca;
                             keypressed;
                         end;
                 end;

            if aceitaHabilit and (habil >= 0) then
                 begin
                     if boolean(habil) <> habilit then
                         keyboardClick (' ');
                     keyBoardClick (TAB);
                 end;
        end;

    delay (500);
end;

{---------------------------------------------------------------------}

procedure reconfig;
var c, c2: char;
    cn, m, vol: integer;
begin
    mensagem ('MXVOLPAD', 0);     {'Qual o volume padrão de 0 a 100  '}
    sintReadInt (vol);
    if (vol < 0) or (vol > 100) then
        vol := 50;

    mensagem ('MXLIGMIC', 0);     {'Liga eco do microfone ? '}
    sintLeTecla (c, c2);
    writeln;
    ligaEcoMic := upcase(c) = 'S';

    mensagem ('MXRECONF', 1);     {'Reconfigurando todo mixer, espere sem teclar nada'}

    trocaJan (janMixer);
    for m := 0 to 1 do
        begin
            selModo (m);
            pegaCanaisAtivos;
            for cn := 1 to ncanais do
                with canal[cn] do
                    begin
                         sintWrite (nomeCanal);
                         if copy (nomeCanal, 1, 3) = 'Mic' then
                             acertaCanal (m, cn, 50, vol, integer(ligaEcoMic))
                         else
                             acertaCanal (m, cn, 50, vol, integer(true));
                         writeln;
                    end;
        end;

    trocaJan (minhaJan);
    mensagem ('MXOK', 1);         {'Ok'}
end;

{--------------------------------------------------------}

function folheiaCanais (m: integer): integer;
var
    c: char;
    ncan: integer;

    procedure ultimoCanal;
    begin
        textBackGround (MAGENTA);
        mensagem ('MXULTCAN', 0);  {'Último canal...'}
        textBackGround (BLACK);
        writeln;
    end;

begin
    ncan := 0;
    repeat
        c := readkey;
        if c = #0 then
            begin
                c := readkey;
                case c of
                    BAIX:   begin
                                ncan := ncan + 1;
                                if ncan > ncanais then
                                    begin
                                        ncan := ncanais + 1;
                                        ultimoCanal;
                                    end
                                else
                                    sintWriteln (canal[ncan].nomeCanal);
                            end;

                    CIMA:   begin
                                ncan := ncan - 1;
                                if ncan < 1 then
                                    begin
                                        ncan := 0;
                                        ultimoCanal;
                                    end
                                else
                                    sintWriteln (canal[ncan].nomeCanal);
                            end;

                    ESQ:   if (ncan > 0) and (ncan <= nCanais) then
                                    sintWriteln (canal[ncan].nomeCanal);

                    DIR:   if (ncan > 0) and (ncan <= nCanais) then
                                    sintSoletra (canal[ncan].nomeCanal);
                end;
            end
        else
            begin
                if (c = ENTER) and
                   (ncan <= 0) or (ncan > nCanais) then
                       c := ESC;
            end;

    until (c = ESC) or (c = ENTER);

    if c = ESC then
        folheiaCanais := 0
    else
        folheiaCanais := ncan;
end;

{---------------------------------------------------------------------}

function leNovoValor (v: longint; min, max: integer): longint;
var erro: integer;
    s: string;
label inicio;

begin
    leNovoValor := v;
inicio:
    mensagem ('MXNOVVAL', 0);   {'Novo valor (enter deixa igual) '}

    sintReadln (s);
    if s = '' then exit;

    val (s, v, erro);
    if (erro <> 0) or (v < min) or (v > max) then
        begin
            mensagem ('MXERRVAL', 1);   {'Valor inválido, redigite, ESC desiste'}
            goto inicio;
        end;

    leNovoValor := v;
end;

{---------------------------------------------------------------------}

procedure controlesAvancados (m, cn: integer);
var graves, agudos, bal: integer;
begin
graves := 50;
agudos := 50;

    with canal [cn] do
        begin
            if aceitaBalanco then
                begin
                    mensagem ('MXBALANC', 0);   {'Balanco '}
                    mensagem ('MXVALATU', 0);   {'Valor '}
                    sintWriteint (trunc ((balanco / 63) * 100));
                    write ('  ');
                    bal := leNovoValor (balanco, 0, 100);
                    if bal <> balanco then
                        begin
                            trocaJan (janMixer);
                            acertaCanal (m, cn, bal, -1, -1);
                            trocaJan (minhaJan);
                        end;
                end;

            if aceitaGraves then
                begin
                    mensagem ('MXGRAVES', 0);   {'Graves  '}
                    mensagem ('MXVALATU', 0);   {'Valor '}
                    sintWriteint (trunc ((graves / 255) * 100));
                    write ('  ');
                    graves := leNovoValor (graves, 0, 100);

                    {... acertar ...}

                end;

            if aceitaAgudos then
                begin
                    mensagem ('MXAGUDOS', 0);   {'Agudos  '}
                    mensagem ('MXVALATU', 0);   {'Valor '}
                    sintWriteint (trunc ((graves / 255) * 100));
                    write ('  ');
                    graves := leNovoValor (graves, 0, 100);

                    {... acertar ...}
                end;

             { acertar microfone:   MXAGC }

        end;
end;

{---------------------------------------------------------------------}

procedure editaCanal (m, cn: integer);
var c, c2: char;
    bal, vol: integer;
    hab: boolean;

     procedure atualiza;
     begin
         trocaJan (janMixer);
         acertaCanal (m, cn, bal, vol, integer(hab));
         trocaJan (minhaJan);
     end;

begin
    with canal [cn] do
        begin
            bal := -1;
            vol := volume;
            hab := habilit;

            if aceitaHabilit then
                begin
                    mensagem ('MXPOSHAB', 0);     {'Posso habilitar ? '}
                    sintLeTecla (c, c2);
                    writeln;
                    hab := upcase (c) <> 'N';
                end;

            if (not hab) and habilit then
                begin
                    atualiza;
                    exit;
                end;

            if aceitaVolume then
                begin
                     mensagem ('MXVOLUME', 0);   {'Volume  '}
                     mensagem ('MXVALATU', 0);   {'Valor '}
                     sintWriteint (trunc ((volume / 255) * 100));
                     write ('  ');
                     vol := leNovoValor (volume, 0, 100);
                     if (vol <> volume) or (habilit <> hab) then atualiza;
                end;

           if aceitaAvancado or aceitaBalanco then
                begin
                    mensagem ('MXCMAVAN', 0);     {'Quer fazer ajustes avançados ? '}
                    sintLeTecla (c, c2);
                    writeln;
                    if upcase (c) = 'S' then
                         controlesAvancados (m, cn);
                end;
        end;
end;

{---------------------------------------------------------------------}

procedure altera (m: integer);
var cn: integer;
begin
    trocaJan (janMixer);
    selModo (m);
    pegaCanaisAtivos;

    trocaJan (minhaJan);
    mensagem ('MXUSESET', 1);   {'Use as setas depois enter para selecionar o canal'}

    cn := folheiaCanais (m);
    if cn = 0 then
        begin
            mensagem ('MXDESIS', 1);    {'Desistiu'}
            exit;
        end;

    writeln;
    mensagem ('MXALTERA', 0);
    sintWriteln (canal[cn].nomeCanal);

    editaCanal (m, cn);

    trocaJan (minhaJan);
    mensagem ('MXOK', 1);         {'Ok'}
end;

{--------------------------------------------------------}

procedure finaliza;
var i: integer;
    volume: integer;
begin
    trocaJan (janMixer);

    playInit (300);
    playVirtKey (VK_F4, false, false, true, 1);
    playStart;
    while  playIsActive do
        begin
            calaboca;
            keypressed;
        end;

    trocaJan (minhaJan);

    mensagem ('MXFIM', 1);    {'Mixer fechado'}
    sintFim;
    delay (1000);
    doneWinCrt;
end;

{---------------------------------------------------------------------}


var processando: boolean;
    c, c2: char;

begin
    inicializa;

    processando := true;
    repeat
        mensagem ('MXQUALOP', 0);   {'Qual opção: '}
        sintLeTecla (c, c2);
        writeln;
        while sintFalando do;

        case upcase(c) of
             'R':  reconfig;
             'A':  altera (0);
             'G':  altera (1);

             ESC:  processando := false;

        else
             mensagem ('MXAJUDA', 1);   { ajuda... }
        end;
    until not processando;

    finaliza;
end.
