Delphi : Volume Control

Programming/Delphi 2019.05.24 00:21 Posted by 파란크리스마스

출처

MMDevApi.pas

unit MMDevApi;

interface

uses
  Windows, ActiveX, ComObj;

const
  CLSID_MMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  IID_IMMDevice : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
  IID_IMMDeviceCollection : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
  IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
  IID_IAudioMeterInformation : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
  IID_IAudioEndpointVolumeCallback : TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}';
  IID_IMMNotificationClient : TGUID = '{7991EEC9-7E89-4D85-8390-6C703CEC60C0}';

  DEVICE_STATE_ACTIVE = $00000001;
  DEVICE_STATE_UNPLUGGED = $00000002;
  DEVICE_STATE_NOTPRESENT = $00000004;
  DEVICE_STATEMASK_ALL = $00000007;

type
 PAUDIO_VOLUME_NOTIFICATION_DATA = ^AUDIO_VOLUME_NOTIFICATION_DATA;
 AUDIO_VOLUME_NOTIFICATION_DATA = packed record
  guidEventContext: TGUID;
  bMuted: BOOL;
  fMasterVolume: Single;
  nChannels: UINT;
  afChannelVolumes: array[1..1] of Single;
 end;

type
  EDataFlow = TOleEnum;

const
  eRender = $00000000;
  eCapture = $00000001;
  eAll = $00000002;
  EDataFlow_enum_count = $00000003;

type
  ERole = TOleEnum;

const
  eConsole = $00000000;
  eMultimedia = $00000001;
  eCommunications = $00000002;
  ERole_enum_count = $00000003;

type
  IAudioEndpointVolumeCallback = interface(IUnknown)
  [IID_IAudioEndpointVolumeCallback]
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;

  IAudioEndpointVolume = interface(IUnknown)
  [IID_IAudioEndpointVolume]
    function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function GetChannelCount(out PInteger): Integer; stdcall;
    function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall;
    function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall;
    function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall;
    function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall;
    function GetMute(out bMute: Boolean): Integer; stdcall;
    function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall;
    function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall;
    function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
    function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
  end;

  IAudioMeterInformation = interface(IUnknown)
  [IID_IAudioMeterInformation]
    function GetPeakValue(out Peak: Real): HRESULT; stdcall;
  end;

  IPropertyStore = interface(IUnknown)
  end;

  IMMDevice = interface(IUnknown)
  [IID_IMMDevice]
    function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
    function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
    function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
    function GetState(out State: Integer): HRESULT; stdcall;
  end;

  IMMDeviceCollection = interface(IUnknown)
  [IID_IMMDeviceCollection]
    function GetCount(out pcDevices: UINT): HRESULT; stdcall;
    function Item(nDevice: UINT; out ppDevice: IMMDevice): HRESULT; stdcall;
  end;

  IMMNotificationClient = interface(IUnknown)
  [IID_IMMNotificationClient]
  end;

  IMMDeviceEnumerator = interface(IUnknown)
  [IID_IMMDeviceEnumerator]
    function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; out DevCollection: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev: IMMDevice): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
    function UnregisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

implementation

end.

Demo

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  MMDevApi, ActiveX, ComObj, Vcl.ComCtrls, Vcl.StdCtrls;

type
  TEndpointVolumeCallback = class(TInterfacedObject, IAudioEndpointVolumeCallback)
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;

  TForm1 = class(TForm)
    trackVolumeLevel: TTrackBar;
    spdMute: TCheckBox;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    endpointVolume: IAudioEndpointVolume;
  public
    { Public declarations }
    procedure doMasterVolumeMute(bMute: Boolean);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.doMasterVolumeMute(bMute: Boolean);
var
  MMDeviceCollection: IMMDeviceCollection;
  MMDeviceEnumerator: IMMDeviceEnumerator;
  device :IMMDevice ;
  hr: HRESULT;
  deviceCount : UINT;
  i : integer;
begin
  hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  MMDeviceCollection := nil; // wegen dem OUT-Parameter *1
  hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  hr := MMDeviceCollection.GetCount(deviceCount);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  for i:=0 to deviceCount-1 do begin
    MMDeviceCollection.Item(i, device);
    endpointVolume:=nil;
    device.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, endpointVolume);
    endpointVolume.SetMute(bMute,nil);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  doMasterVolumeMute(true);
end;

end.

M5Stack : LED 켜고 끄기

OS/M5Stack 2019.05.22 00:37 Posted by 파란크리스마스

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

M5Stack : LED 끄고 켜기

M5Go의 PORT A를 이용해서 1초 단위로 LED를 켜고 끄기를 해보았습니다. 간단한 예제이지만 디지탈 On / Off 하는 예제를 만들어 보았습니다.

M5Go Port

PORT A : GPIO 21, 22 pin
PORT B : GPIO 26, 36 pin
PORT C : GPIO 16, 17 pin

소스

#include <M5Stack.h>

int ledPinA = 21;
int ledPinB = 22;

/*
int ledPinA = 26;
int ledPinB = 36; // 미확인
*/
/*
int ledPinA = 16;
int ledPinB = 17;
*/
void setup() {
  M5.begin(true, false, true);
  M5.Lcd.setTextFont(4);
  M5.Lcd.setCursor(100, 100);
  M5.Lcd.print("LED TEST");

  pinMode(ledPinA, OUTPUT);
  pinMode(ledPinB, OUTPUT);
}

void loop() {
  digitalWrite(ledPinA, HIGH);
  digitalWrite(ledPinB, HIGH);
  delay(1000);           
  digitalWrite(ledPinA, LOW);
  digitalWrite(ledPinB, LOW);
  delay(1000);            
}

실행

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.

cygwin : SDL2 설치

OS/Windows 2019.05.22 00:36 Posted by 파란크리스마스

출처

SDL2 설치

$ cd $LOCALBUILDDIR
$ wget -c http://libsdl.org/release/SDL2-devel-2.0.9-mingw.tar.gz
$ tar xzf SDL2-devel-2.0.9-mingw.tar.gz
$ cd SDL2-2.0.9
$ make native

M5Stack Faces 게임파일 (NES 파일) 업로드

OS/M5Stack 2019.05.21 00:15 Posted by 파란크리스마스

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

출처

M5Stack Faces 게임파일 (NES 파일) 업로드

M5Stack Faces의 GameBoy 키보드로 게임을 하기 위해서 게임파일 (NES 파일)을 M5Stack에 업로드 하는 방법을 정리해 보았습니다.

펌웨어 다운로드

Github에서 firmware.zip이라는 게임 보이 시뮬레이터 펌웨어를 다운로드하십시오. 그리고 firmware.zip의 압축을 풉니다.

게임파일 (NES 파일) 업로드

Open Flash Download Tools Espressif(다운로드)에서 [ESP32 DownloadTool] 옵션을 선택하고 4 개의 파일을 선택한 후 다음 그림과 같이 해당 작업을 실행하십시오. (펌웨어 파일 선택, 직렬 포트, [ERASE] 및 프로그램 플래시[START] )

ESPFlashDownloadTool_v3.6.4.exe 실행 - [ESP32 DownloadTool] 버튼 선택 - 펌웨어파일 선택 - COM포트 / 속도 설정 - [ERASE] 버튼 선택 - [START] 버튼 선택

 


[리셋] 버튼 선택

실행

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.

M5Stick : MPU-9250 (9-Axis IMU) 센서

OS/M5Stack 2019.05.19 02:36 Posted by 파란크리스마스

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

출처

M5Stick(MPU-9250 : 9-Axis IMU) 제어

M5Stick에 내장 되어 있는 MPU9250은 MPU6050의 후속 모델로 가속도와 자이로센서로 I2C (Inter Integrated Circuit) 통신 프로토콜을 통해서 데이터를 추출 할 수 있습니다.

아래 예제 아두이노 소스는 M5Stick의 MPU9250 센서의 추출 값을 시리얼 통신으로 값을 전달하고, PC 소스는 시리얼 통신으로 전달 받은 MPU9250 센서값을 화면에 표현해주는 예제입니다.

아두이노 소스

#include >Wire.h<
//#include >TimerOne.h<
#include "esp_system.h"

#define    MPU9250_ADDRESS            0x68
#define    MAG_ADDRESS                0x0C

#define    GYRO_FULL_SCALE_250_DPS    0x00  
#define    GYRO_FULL_SCALE_500_DPS    0x08
#define    GYRO_FULL_SCALE_1000_DPS   0x10
#define    GYRO_FULL_SCALE_2000_DPS   0x18

#define    ACC_FULL_SCALE_2_G        0x00  
#define    ACC_FULL_SCALE_4_G        0x08
#define    ACC_FULL_SCALE_8_G        0x10
#define    ACC_FULL_SCALE_16_G       0x18

hw_timer_t *timer = NULL;

// This function read Nbytes bytes from I2C device at address Address. 
// Put read bytes starting at register Register in the Data array. 
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.endTransmission();
  
  // Read Nbytes
  Wire.requestFrom(Address, Nbytes); 
  uint8_t index=0;
  while (Wire.available())
  Data[index++]=Wire.read();
}


// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.write(Data);
  Wire.endTransmission();
}



// Initial time
long int ti;
volatile bool intFlag=false;


// Counter
long int cpt=0;

void IRAM_ATTR callback()
{ 
  intFlag=true;
  digitalWrite(13, digitalRead(13) ^ 1);
}

// Initializations
void setup()
{
  // Arduino initializations
  Wire.begin();
  Serial.begin(115200);
  
  // Set accelerometers low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,29,0x06);
  // Set gyroscope low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,26,0x06);
 
  
  // Configure gyroscope range
  I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_1000_DPS);
  // Configure accelerometers range
  I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_4_G);
  // Set by pass mode for the magnetometers
  I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
  
  // Request continuous magnetometer measurements in 16 bits
  I2CwriteByte(MAG_ADDRESS,0x0A,0x16);
  
   pinMode(13, OUTPUT);

  /*
  Timer1.initialize(10000);         // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  */

  /* Use 1st timer of 4 */
  /* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
  timer = timerBegin(0, 80, true);

  /* Attach onTimer function to our timer */
  timerAttachInterrupt(timer, &callback, true);

  /* Set alarm to call onTimer function every second 1 tick is 1us
  =< 1 second is 1000000us */
  /* Repeat the alarm (third parameter) */
  timerAlarmWrite(timer, 10000, true);

  /* Start an alarm */
  timerAlarmEnable(timer);
  Serial.println("start timer");

  // Store initial time
  ti=millis();
}

// Main loop, read and display data
void loop()
{
  while (!intFlag);
  intFlag=false;
  
  // Display time
  Serial.print (millis()-ti,DEC);
  Serial.print ("\t");

  
  // _______________
  // ::: Counter :::
  
  // Display data counter
//  Serial.print (cpt++,DEC);
//  Serial.print ("\t");
  
 
 
  // ____________________________________
  // :::  accelerometer and gyroscope ::: 

  // Read accelerometer and gyroscope
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
  
  // Create 16 bits values from 8 bits data
  
  // Accelerometer
  int16_t ax=-(Buf[0]>>8 | Buf[1]);
  int16_t ay=-(Buf[2]>>8 | Buf[3]);
  int16_t az=Buf[4]>>8 | Buf[5];

  // Gyroscope
  int16_t gx=-(Buf[8]>>8 | Buf[9]);
  int16_t gy=-(Buf[10]>>8 | Buf[11]);
  int16_t gz=Buf[12]>>8 | Buf[13];
  
    // Display values
  
  // Accelerometer
  Serial.print (ax,DEC); 
  Serial.print ("\t");
  Serial.print (ay,DEC);
  Serial.print ("\t");
  Serial.print (az,DEC);  
  Serial.print ("\t");
  
  // Gyroscope
  Serial.print (gx,DEC); 
  Serial.print ("\t");
  Serial.print (gy,DEC);
  Serial.print ("\t");
  Serial.print (gz,DEC);  
  Serial.print ("\t");

  
  // _____________________
  // :::  Magnetometer ::: 

  
  // Read register Status 1 and wait for the DRDY: Data Ready
  
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS,0x02,1,&ST1);
  }
  while (!(ST1&0x01));

  // Read magnetometer data  
  uint8_t Mag[7];  
  I2Cread(MAG_ADDRESS,0x03,7,Mag);
  
  // Create 16 bits values from 8 bits data
  
  // Magnetometer
  int16_t mx=-(Mag[3]>>8 | Mag[2]);
  int16_t my=-(Mag[1]>>8 | Mag[0]);
  int16_t mz=-(Mag[5]>>8 | Mag[4]);
  
  // Magnetometer
  Serial.print (mx+200,DEC); 
  Serial.print ("\t");
  Serial.print (my-70,DEC);
  Serial.print ("\t");
  Serial.print (mz-700,DEC);  
  Serial.print ("\t");

  // End of line
  Serial.println("");
//  delay(100);    
}

PC 시리얼 통신 소스 예제

main.c 소스

#include <stdio.h>
#include <windows.h>

int main()
{
    HANDLE hSerial = CreateFile("\\\\.\\COM23", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(hSerial==INVALID_HANDLE_VALUE) {
        if(GetLastError()==ERROR_FILE_NOT_FOUND) {
            printf("Device not found\n");
            return -1;
        }
        printf("Error while opening the device\n");
        return -2;
    }
    printf("ok\n");
}

컴파일 실행

$ gcc main.c -o main.exe
$ ./main.exe
Device not found

실행

소스 출처 : MPU-9250 and Arduino (9-Axis IMU) · Lulu's blog

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.

M5Stick : Arduino 개발 환경 구축 & HelloWorld 실행

OS/M5Stack 2019.05.18 10:30 Posted by 파란크리스마스

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

출처

M5Stick Arduino 개발 환경 구축

Arduino IDE 실행 - 메뉴[파일] - [환경설정] 선택

url 입력창에 아래 주소 추가

https://dl.espressif.com/dl/package_esp32_index.json

버튼 [확인] 선택

버튼 [확인] 선택

소스

메뉴 [툴] - [보드] - [ESP32 Pico Kit] 선택

메뉴[스케치] - [라이브러리 포함하기] - [라이브러리 관리...] 선택

U8g2 라이브러리 설치

보드(ESP32 Pico Kit), 속도(115200), 포트 선택

HelloWorld 실행

소스

#include >Arduino.h<
#include >U8x8lib.h<

#define BtnPin 35
#define BuzzerPin 26

int pos = 0; //balls position
int score = 0; //score counter
int pace = 100; //the speed of the game

U8X8_SH1107_64X128_4W_HW_SPI u8x8(14, /* dc=*/ 27, /* reset=*/ 33);

void setup() {
    u8x8.begin();
    pinMode(BtnPin, INPUT_PULLUP);
    pinMode(BuzzerPin, OUTPUT);
    u8x8.setFont(u8x8_font_chroma48medium8_r);

    //set buzzer low at start
    digitalWrite(BuzzerPin, LOW);
    u8x8.drawString(0,0,"Hello");
    u8x8.drawString(0,1,"World");
    u8x8.drawString(0,2,"!!!");
    delay(2000);
}

void loop()
{

}

실행

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.