Você está aqui: C++ ::: Dicas & Truques ::: MIDI Musical Instrument Digital Interface, Mapeamento e sequenciamento MIDI, Entrada e saída MIDI |
Programação MIDI usando C++ - Como usar um vetor de chars para construir uma mensagem MIDI e passá-lo para a função midiOutShortMsg() da API do WindowsQuantidade de visualizações: 2226 vezes |
Nas dicas dessa seção nós vimos como é possível enviar uma mensagem MIDI para o dispositivo de saída por meio da função midiOutShortMsg() da API do Windows. Essa função recebe um handle para o dispositivo de saída MIDI e um valor DWORD contendo a mensagem MIDI. Se você revisitar essas dicas, verá que na maioria delas nós informamos a mensagem MIDI diretamente no parâmetro da função (como um valor hexadecimal). Nesta dica mostrarei como é possível construir as mensagens MIDI usando seus valores individuais e, o que é melhor, usando valores decimais. Para isso nós vamos construir um vetor de char e informar os valores que compõem a mensagem. É importante observar que a função midiOutShortMsg() exige que a mensagem MIDI seja informada na ordem de bytes "little endian" ou seja, o status MIDI é informado no byte de ordem mais baixa. Isso é conseguido com um cast do vetor para um unsigned long. Veja o trecho de código: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- // vamos criar um vetor contendo os valores que compõem a mensagem MIDI unsigned char vetor[4]; vetor[0] = 144; // Note-on no Canal 1 vetor[1] = 40; // Nota Mi na 4ª oitava vetor[2] = 100; // Velocidade/volume da nota vetor[3] = 0; // Não é usado // e aqui é que acontece a mágica. Quando fazemos o cast do // vetor para o tipo long sem sinal, os valores são colocados em // little endian, justamente a ordem de bytes esperada pela // função midiOutShortMsg() unsigned long mensagem = *(unsigned long*)vetor; // envia a mensagem MIDI midiOutShortMsg(saida, mensagem); Note que não coloquei o código todo. Para completá-lo, veja outras dicas dessa seção. |
Link para compartilhar na Internet ou com seus amigos: |
C++ ::: Dicas & Truques ::: Programação Orientada a Objetos |
Programação Orientada a Objetos em C++ - Como usar construtores em suas classes C++Quantidade de visualizações: 15781 vezes |
Quando um objeto de uma classe C++ é criado, a linguagem chama um construtor para tal classe. Se nenhum construtor estiver definido, um construtor padrão é invocado. Este construtor aloca memória para o objeto, mas não o inicializa. Um construtor é um método que definimos em nossas classes C++ e que possui o mesmo nome da classe. Um construtor não possui tipo de retorno e não retorna nenhum valor. Em geral construtores são públicos, mas, é possível termos construtores privados. Neste caso, somente um método estático da classe poderia criar novos objetos da classe (quando puder dê uma olhada no padrão de projeto Singleton). O uso mais frequente dos métodos construtores é quando queremos inicializar valores das variáveis e demais recursos no momento da criação de uma nova instância da classe. Esta é uma técnica útil, visto que não precisamos dispor de esforço extra para inicializar as variáveis de instância de um objeto, individualmente, após sua criação. Vamos ver um exemplo da definição e uso de construtores em uma classe C++? Comece analisando o código para o arquivo de definição da classe Pessoa: Código para Pessoa.h: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- // vamos evitar múltiplas inclusões do // arquivo de cabeçalho (header file) #ifndef PESSOA_H #define PESSOA_H // vamos incluir o header string #include <string> using namespace std; class Pessoa{ public: // construtor da classe Pessoa Pessoa(string, string, int); // método que permite retornar o nome da pessoa string getNome(); // método que permite retornar o e-mail da pessoa string getEmail(); // método que permite retornar a idade da pessoa int getIdade(); private: // variáveis privadas string nome; string email; int idade; }; #endif Veja a assinatura do método construtor: Pessoa(string, string, int); Note que na lista de parâmetros do construtor não precisamos informar os nomes dos parâmetros, apenas seus tipos. Veja agora o arquivo de implementação para esta classe: Código para Pessoa.cpp: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- // arquivo de implementação para a // classe Pessoa // vamos incluir o header Pessoa.h #include "Pessoa.h" // implementação do construtor Pessoa::Pessoa(string nome, string email, int idade){ this->nome = nome; this->email = email; this->idade = idade; } // método que permite obter o nome da pessoa string Pessoa::getNome(){ return this->nome; } // método que permite obter o email da pessoa string Pessoa::getEmail(){ return this->email; } // método que permite obter a idade da pessoa int Pessoa::getIdade(){ return this->idade; } Note que na implementação do método construtor nós recebemos os argumentos para os parâmetros e os usamos para inicializar as variáveis privadas da instância da classe. Observe o uso do ponteiro this para nos referirmos à instância atual da classe Pessoa. Finalmente, veja o código para o método main() do programa. É aqui que criamos um novo objeto da classe Pessoa e usamos seu método construtor para inicializar suas variáveis privadas de uma só vez: Código para main.cpp: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- #include <cstdlib> #include <iostream> // vamos incluir a classe Pessoa #include "Pessoa.h" using namespace std; int main(int argc, char *argv[]) { // vamos criar um novo objeto da classe Pessoa Pessoa *p = new Pessoa("Osmar J. Silva", "osmar@arquivodecodigos.net", 38); // vamos exibir os dados da pessoa cout << "Nome: " << p->getNome() << endl; cout << "E-Mail: " << p->getEmail() << endl; cout << "Idade: " << p->getIdade() << endl; system("PAUSE"); return EXIT_SUCCESS; } Além do construtor, uma classe C++ possui também um método destrutor. Veja minhas dicas relacionadas a este assunto para aprender como definir e usar destrutores em suas classes C++. |
C++ ::: Dicas & Truques ::: Ponteiros, Referências e Memória |
Como usar ponteiros em C++ - Apostila de C++ para iniciantesQuantidade de visualizações: 7997 vezes |
Antes de pensarmos em ponteiros, é importante nos lembrarmos de alguns aspectos referentes à variáveis. Dependendo do seu conhecimento de programação, você deve saber que variáveis possuem nomes que as identificam durante a execução do programa. Você deve saber também que uma variável armazena um valor (que pode ser fixo, no caso de uma constante, ou pode mudar durante a execução de seus códigos). O que poucos programadores se lembram é que uma variável possui um endereço, e que o nome da variável não é nada mais que um apelido para a localização deste endereço. Desta forma, um ponteiro não é nada mais que um tipo especial de variável que armazena o endereço de outra. Veja um exemplo: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- #include <iostream> using namespace std; int main(int argc, char *argv[]){ // variável do tipo int int valor = 10; // ponteiro para uma variável do tipo int int *p = &valor; // exibe o valor da variável "valor", apontada // pelo ponteiro p cout << *p << endl; system("PAUSE"); // pausa o programa return EXIT_SUCCESS; } Neste código nós temos a declaração e definição de duas variáveis: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- int valor = 10; int *p = &valor; A primeira variável é uma variável do tipo int e a segunda é um ponteiro para uma variável do tipo int. Veja que devemos sempre usar "*" antes do nome de um ponteiro em sua declaração. O símbolo "&" serve para indicar que estamos acessando o endereço de uma variável e não o seu conteúdo. O resultado destas duas linhas é que agora temos um ponteiro que nos permite acessar e manipular a variável valor. Observe a linha: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- cout << *p << endl; Aqui nós estamos acessando o valor da variável apontada por p. Veja o uso do símbolo "*" para acessar o valor da variável. Isso é chamado de desreferenciamento de ponteiros. Pareceu complicado? Veja uma linha de código que altera indiretamente o valor da variável valor para 30: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- *p = 30; Ponteiros são ferramentas muito importantes na programação em C++. No entanto, é preciso ter muito cuidado ao lidar com eles. A primeira coisa a ter em mente é que um ponteiro não está apontando para nenhum lugar até que atribuimos a ele o endereço de uma outra variável. E é aí que mora o perigo. Um programa entra em colapso absoluto se tentarmos acessar um ponteiro que aponta para um local de memória que já foi liberado novamente ao sistema. No caso menos grave, estaremos tentando acessar locais de memória inválidos ou reservados a outros programas ou tarefas do sistema operacional. Isso me lembra os velhos tempos da tela azul de morte. |
C++ ::: Dicas & Truques ::: MIDI Musical Instrument Digital Interface, Mapeamento e sequenciamento MIDI, Entrada e saída MIDI |
Como definir o tipo de instrumento (programa) em um evento MIDI e enviar a mensagem para a função midiOutShortMsg() da API Win32 do WindowsQuantidade de visualizações: 981 vezes |
Vimos em dicas nessa seção como usar a função midiOutShortMsg() da API Win32 do Windows para tocar notas musicais no dispositivo de saída MIDI. No entanto, nos exemplos anteriores, a nota tocada foi no instrumento padrão, ou seja, Acoustic Grand Piano, e no canal 1. Nesta dica mostrarei como definir o instrumento e também falarei um pouco mais sobre como tocar as notas em canais diferentes. Vamos então, com muita atenção. Analisando a documentação MIDI, encontramos que uma mudança de programa (instrumento musical) no canal 1 é representada pelo código de status 192 (hexadecimal C0), seguido pelo código do instrumento a ser usado (um valor inteiro que vai de 0 a 127, e que deverá ser convertido em hexadecimal). Assim, é bom dar uma olhada nessa lista: Piano Timbres: 1 Acoustic Grand Piano 2 Bright Acoustic Piano 3 Electric Grand Piano 4 Honky-tonk Piano 5 Rhodes Piano 6 Chorused Piano 7 Harpsichord 8 Clavinet Chromatic Percussion: 9 Celesta 10 Glockenspiel 11 Music Box 12 Vibraphone 13 Marimba 14 Xylophone 15 Tubular Bells 16 Dulcimer Organ Timbres: 17 Hammond Organ 18 Percussive Organ 19 Rock Organ 20 Church Organ 21 Reed Organ 22 Accordion 23 Harmonica 24 Tango Accordion Guitar Timbres: 25 Acoustic Nylon Guitar 26 Acoustic Steel Guitar 27 Electric Jazz Guitar 28 Electric Clean Guitar 29 Electric Muted Guitar 30 Overdriven Guitar 31 Distortion Guitar 32 Guitar Harmonics Bass Timbres: 33 Acoustic Bass 34 Fingered Electric Bass 35 Plucked Electric Bass 36 Fretless Bass 37 Slap Bass 1 38 Slap Bass 2 39 Synth Bass 1 40 Synth Bass 2 String Timbres: 41 Violin 42 Viola 43 Cello 44 Contrabass 45 Tremolo Strings 46 Pizzicato Strings 47 Orchestral Harp 48 Timpani Ensemble Timbres: 49 String Ensemble 1 50 String Ensemble 2 51 Synth Strings 1 52 Synth Strings 2 53 Choir "Aah" 54 Choir "Ooh" 55 Synth Voice 56 Orchestral Hit Brass Timbres: 57 Trumpet 58 Trombone 59 Tuba 60 Muted Trumpet 61 French Horn 62 Brass Section 63 Synth Brass 1 64 Synth Brass 2 Reed Timbres: 65 Soprano Sax 66 Alto Sax 67 Tenor Sax 68 Baritone Sax 69 Oboe 70 English Horn 71 Bassoon 72 Clarinet Pipe Timbres: 73 Piccolo 74 Flute 75 Recorder 76 Pan Flute 77 Bottle Blow 78 Shakuhachi 79 Whistle 80 Ocarina Synth Lead: 81 Square Wave Lead 82 Sawtooth Wave Lead 83 Calliope Lead 84 Chiff Lead 85 Charang Lead 86 Voice Lead 87 Fifths Lead 88 Bass Lead Synth Pad: 89 New Age Pad 90 Warm Pad 91 Polysynth Pad 92 Choir Pad 93 Bowed Pad 94 Metallic Pad 95 Halo Pad 96 Sweep Pad Synth Effects: 97 Rain Effect 98 Soundtrack Effect 99 Crystal Effect 100 Atmosphere Effect 101 Brightness Effect 102 Goblins Effect 103 Echoes Effect 104 Sci-Fi Effect Ethnic Timbres: 105 Sitar 106 Banjo 107 Shamisen 108 Koto 109 Kalimba 110 Bagpipe 111 Fiddle 112 Shanai Sound Effects: 113 Tinkle Bell 114 Agogo 115 Steel Drums 116 Woodblock 117 Taiko Drum 118 Melodic Tom 119 Synth Drum 120 Reverse Cymbal Sound Effects: 121 Guitar Fret Noise 122 Breath Noise 123 Seashore 124 Bird Tweet 125 Telephone Ring 126 Helicopter 127 Applause 128 Gun Shot A especificação MIDI define que o canal 10 seja reservado para os kits de percussão. Os instrumentos abaixo possuem os números de notas a serem enviados neste canal. 35 Acoustic Bass Drum 36 Bass Drum 1 37 Side Stick 38 Acoustic Snare 39 Hand Clap 40 Electric Snare 41 Low Floor Tom 42 Closed High Hat 43 High Floor Tom 44 Pedal High Hat 45 Low Tom 46 Open High Hat 47 Low Mid Tom 48 High Mid Tom 49 Crash Cymbal 1 50 High Tom 51 Ride Cymbal 1 52 Chinese Cymbal 53 Ride Bell 54 Tambourine 55 Splash Cymbal 56 Cowbell 57 Crash Cymbal 2 58 Vibraslap 59 Ride Cymbal 2 60 High Bongo 61 Low Bongo 62 Mute High Conga 63 Open High Conga 64 Low Conga 65 High Timbale 66 Low Timbale 67 High Agogo 68 Low Agogo 69 Cabasa 70 Maracas 71 Short Whistle 72 Long Whistle 73 Short Guiro 74 Long Guiro 75 Claves 76 High Wood Block 77 Low Wood Block 78 Mute Cuica 79 Open Cuica 80 Mute Triangle 81 Open Triangle É uma lista bem longa e ficará a ser cargo estudá-la ou usá-la como referência. Meu interesse maior é o código C/C++. Assim, vamos ver logo como definir o instrumento no canal 1 como Overdriven Guitar. Este instrumento possui o código 30 mas, na programação, devemos diminuí-lo em 1, ficando 29, e, ao passarmos para hexadecimal teremos 1D. A mudança de programa no canal 1 é representada pelo código 192, o que em hexadecimal é C0. Pronto, agora basta construirmos o DWORD da forma que fizemos nas dicas anteriores e chamar a função midiOutShortMsg(). Veja: ---------------------------------------------------------------------- Se precisar de ajuda com o código abaixo, pode me chamar no WhatsApp +55 (62) 98553-6711 (Osmar) ---------------------------------------------------------------------- #include <cstdlib> #include <iostream> #include <windows.h> using namespace std; int main(int argc, char *argv[]) { unsigned int erro; // guarda o erro caso algo dê errado HMIDIOUT saida; // handle para o dispositivo de saída MIDI. // vamos abrir o dispositivo de saída MIDI erro = midiOutOpen(&saida, MIDI_MAPPER, 0, 0, CALLBACK_NULL); if (erro != MMSYSERR_NOERROR) { printf("Não foi possível abrir o mapeador MIDI: %d\n", erro); } else { printf("Mapeador MIDI aberto com sucesso\n"); } // vamos definir o instrumento como Overdriven Guitar // no canal 1 midiOutShortMsg(saida, 0x00001DC0); // vamos tocar o dó central com velocidade 100 midiOutShortMsg(saida, 0x00643C90); Sleep(1000); // a nota vai durar 1 segundo // dispara a mensagem Note-off midiOutShortMsg(saida, 0x00643C80); // agora vamos fechar o dispositivo de saída MIDI midiOutClose(saida); system("PAUSE"); return EXIT_SUCCESS; } Execute esse código e ouça um nota dó sendo tocada na guitarra com uma linda distorção. Se você quiser tocar a nota nó no canal 2 ou canal 3, basta usar C1, C2, e assim por diante. Uma última observação é você ficar atento ao fato de que os códigos de Note-on e Note-off para o canal 1 é 90 e 80 (em hexadecimal). Se for no canal 2, os códigos correspondentes serão 91 e 81 (sempre em hexadecimal). |
Desafios, Exercícios e Algoritmos Resolvidos de C++ |
Veja mais Dicas e truques de C++ |
Dicas e truques de outras linguagens |
Códigos Fonte |
Software de Gestão Financeira com código fonte em PHP, MySQL, Bootstrap, jQuery - Inclui cadastro de clientes, fornecedores e ticket de atendimento Diga adeus às planilhas do Excel e tenha 100% de controle sobre suas contas a pagar e a receber, gestão de receitas e despesas, cadastro de clientes e fornecedores com fotos e histórico de atendimentos. Código fonte completo e funcional, com instruções para instalação e configuração do banco de dados MySQL. Fácil de modificar e adicionar novas funcionalidades. Clique aqui e saiba mais |
Controle de Estoque completo com código fonte em PHP, MySQL, Bootstrap, jQuery - 100% funcional e fácil de modificar e implementar novas funcionalidades Tenha o seu próprio sistema de controle de estoque web. com cadastro de produtos, categorias, fornecedores, entradas e saídas de produtos, com relatórios por data, margem de lucro e muito mais. Código simples e fácil de modificar. Acompanha instruções para instalação e criação do banco de dados MySQL. Clique aqui e saiba mais |
Linguagens Mais Populares |
1º lugar: Java |