top drop menu

Recent Post

목요일, 11월 29

라즈베리파이 구글 어시스턴트–갑자기 에러 gTT관련인듯…

얼마전 까지도 잘 되던게 갑자기 안된다. 이럴때 황당하지 … 처음부터 안되던것도 아니고 아무것도 만진게 없는데 갑자기 안된다. 음성으로 조명 켜기를 시켜 보면 구글 어시스턴트 자체가 꺼져 버린다. 에러는 아래와 같다.


    tkk_expr = re.search(".*?(TKK=.*?;)W.*?", line).group(1)
AttributeError: 'NoneType' object has no attribute 'group'


끝에 저런 에러를 토해내고 중단되어 버린다. 어디서 발생되는 에러인지 찾아 보니 gTTS와 관련이 있는것 같다. 커스텀으로 음성제어 기능을 추가하면서 응답을 gTTS로 하도록 해 놨는데 이부분에서 에러가 나는듯 하다. 검색을 해보니 나만 그런게 아니다. gTTS 서비스에서 뭔가 바뀐게 있는 걸까?

일전에도 비슷한 에러를 만난것 같은데? 그때 찾아 보니 이 이슈는 패치가 되었다고 했었는데…? 음~ 알수가 없다.

이미지 150

/home/pi/env/lib/python3.5/site-packages/gtts_token/gtts_token.py 이 파일의 위 캡처 표시 라인이 문제라고 에러가 나온것이다.

뭐가 문제라는 거야? 잘 동작하다가 왜 ???


문제는 gTTS-token 버전이 업그레이드 되면서 뭔가 발생하는 듯 하다.


https://pypi.org/project/gTTS-token/


업그레이드 된 버전으로 재설치 해주자.

pip uninstall gTTS-token

pip install gTTS-token

이전 버전을 삭제하고 재설치 한다.


정상으로 돌아 옴…

웹 비디오 픽처 인 픽처(PiP) 기능 사용하기

PiP (Picture-in-Picture API)는 웹 페이지가 다른 창 상단에있는 작은 창에서 비디오를 재생할 수있게 해주는 새로운 실험용 웹 플랫폼 API이다. 이 기능은 사용자가 다른 일을하면서 비디오를 계속보고 싶어하는 비디오 사이트, 예를 들어 텍스트 자습서 비디오를 보면서 텍스트 편집기 등에서 코딩하는 비디오 사이트에 유용하다. 브라우저 버전이나 종류에 따라 지원하지 않을 경우가 있다. 크롬 최신 버전은 지원을 한다.


---------- index.html ---------------


<!DOCTYPE html>
<html>
<head>
     <meta charset="utf-8">
     <title>Javascript test 03</title>
     <style>
         body{
             text-align: center;
             display: flex;
             align-items: center;
             justify-content: center;
             flex-direction: column;
         }
         video{
             width: 320px;
             height: auto;
         }

        button{
             margin: 10px auto;
         }

    </style>
</head>
<body>
     <h1 id="title">Javascript Example 03 : PIP 모드에서 영상 재생</h1>

    <video id="video" src="videos/Mountains - 7418.mp4" autoplay loop></video>
     <button id="pipButton">PIP</button>

    <script>
       pipButton.hidden = !document.pictureInPictureEnabled;

      function runPip(){
           if (!document.pictureInPictureElement) {
           video.requestPictureInPicture()
           .catch(error => {
             // Video failed to enter Picture-in-Picture mode.
           });
         } else {
           document.exitPictureInPicture()
           .catch(error => {
             // Video failed to leave Picture-in-Picture mode.
           });
         }
       }


       pipButton.addEventListener('click', function() {
         runPip();
       });
     </script>
</body>
</html>


------------------


아래 사이트에서 확인해 보자.

http://visualssing.dothome.co.kr/javascript/js_example003.html

프로세싱(112) : 연속 이미지를 이용한 캐릭터 애니메이션

연속된 이미지 몇장을 연결해서 보여 주어 애니메이션을 구현해 보자. 마우스를 크릭하면 해당 위치에 나타나게 하자.

--------- processing
Dino dino;
boolean run;
void setup(){
   size(640, 480);
   background(0);
   frameRate(30);
   run = false; 
}
void draw(){
   background(0);
   if(run){
     dino.run();
     if(dino.frame >= 7){
       run = false;
     }
   }
}
class Dino{
   PImage[] images;
   int imageCount;
   int frame;
   float x, y;
  
   Dino(float x, float y){
     this.x  = x;
     this.y = y;
     imageCount = 8;
     frame = 0;
     images =  new PImage[imageCount];
    
     for(int i = 0; i < imageCount; i++){
       String filename = "png/Run ("+i+").png";
       images[i] = loadImage(filename);
       images[i].resize(680/2, 472/2);
     }
   }
  
   void run(){
       image(images[frame], this.x, this.y);
       frame = (frame + 1) % imageCount;
       delay(70);
   }
}
void mousePressed(){
     dino = new Dino(mouseX - 150, mouseY - 100);
     run = true;
}

----------------


수요일, 11월 28

웹 비디오에 자막 넣기–VTT 포맷

웹 브라우저에서 영상에 자막파일을 등록하는 것을 해보자. 자막파일하면 smi나 srt 파일이 유명한데 vtt파일도 비중이 높아 지고 있다고 한다.

이미지 147

간단히 예제 파일을 만들어 보자.

----- index.html -----

<video src="../javascript/videos/Mountains - 7418.mp4" autoplay loop controls>
         <track src="subtitle.kr.vtt" kind="subtitles" srclang="kr" label="기본한국어" default>
         <track src="subtitle.en.vtt" kind="subtitles" srclang="en" label="영어자막">
         Sorry, your browser doesn't support embedded videos
     </video>

------------------


---- subtitle.vtt -----------

WEBVTT - Translation of that film I like

NOTE
이것은 주석 부분입니다. 화면에 표시 되지 않아요.

00:00:01.000 --> 00:00:04.000 line:-3
<b>이 예제는 영상에 자막을 추가하는 연습입니다.</b>
이렇게 태그를 직접 적용 할 수 있습니다.

00:00:05.000 --> 00:00:06.500 position:10% align:start size:100%
<u><i>아름다운 풍경을 감상해 보세요. 위치나 크기도 조절이 가능해요.</i></u>

NOTE 이건 안되는데?

00:00:07.000 --> 00:00:08.000 line:-3
<c.captionstyle>따로 스타일을 지정할 수도 있습니다.</c>

00:00:09.000 --> 00:00:11.000 line:-3
그런데 이렇게 텍스트를 편집하는 방법으로 일일히 만들기는 힘들어요.

00:00:13.000 --> 00:00:14.000 line:-3
- 감사합니다.

-----------

영상과 자막파일을 서버에 업로드 하고 접소개 보면 된다. 데모 사이트에서 확인해 보자.


데모사이트 : http://visualssing.dothome.co.kr/temp/videocaption.html






무료영상편집 다빈치 리졸브(Davinchi Resolve)(2)–자막과 장면전환효과

이제 자막과 영상 클립사이에 장면 전환효과를 넣어 보기로 하자.

이미지 145

상단 탭에서 Effects Library를 선택하자. 비디오 트랜지션과 타이틀이라는 항목이 있다. 다양한 프리셋들이 준비 되어 있다. 원하는 것을 선택해서 타임라인에 드래그 앤 드랍 하거나 영상맨 앞으로 가져가면 표시가 된다.

이미지 146

두개의 영상이 겹쳐지게 트랜지션을 가져다 놓으면 두영상에 걸쳐서 장면 전환이 이루어 진다.  전환 영역역시 끝부분에서 마우스를 끌어서 영역을 변경할 수 있다. 이렇게 해서 나온 최종 결과물을 확인 하자.


영상시대에 필수품 무료 영상편집 툴–다빈치 리졸브(Davinchi Resolve)

아직은 영상을 별로 다루지 않아서 굳이 좋은 영상편집툴이 필요하지 무비메이커으로 충분하다. 그런데 좀더 나은 영상편집툴이 필요하다면 사용해 볼만한 영상편집툴이 있다. 어떤 프로그램인지 설치해서 사용해 보기로 하자. 다빈치 리졸브는 블랙매직디자인에서 만든 영상편집 및 색보정 툴이다. 윈도우, 맥, 리눅스를 지원한다. 스탠다드 버전은 무료로 사용이 가능하다. 이 무료버전 만으로도 일반적인 목적의 용도에는 충분하다고 한다.  RAW파일을 편집할려면 유료버전을 구입해야 한다고 한다. 뭐 굳이… 일단 아래 사이트에서 다운로드 받아 설치 하자.

https://www.blackmagicdesign.com/kr/products/davinciresolve/

이미지 134
이미지 135
기본정보를 입력해 주고 다운로드 받으면 된다.  처음 설치후 기본 세팅하는 화면이 나오면 자신의 환경에 맞게 설정해 주면 된다.
이미지 137
이미지 138
다빈치 리졸브가 실행이 되었다. 오호 그럴싸 하다. 무비메이커에 비해 뭔가 전문가 스러운 화면이다. 음 이제 뭐 부터? 뭐 다를게 있겠어. 프로그램이라는게 다 비슷한 인터페이스를 가지고 있기 마련이다. 간단히 영상과 사진이미지를 가져와서 이어 붙이는 방식의 편집을 해 보기로 하자.
이미지 139
편집에 사용될 파일을 가져오는 것은 간단하다. 폴더에서 드래그 드라하면 된다. 당연히 메뉴를 통해서 가져 올 수 있다. 동영상 3개와 이미지 3개 배경음악 파일을 가져다 놓았다. 미리 사용할 파일들을 모아 놓고 사용한다고 생각하면 된다.  첫번째 영상을 선택하고 드래그 해서 타임라인 비디오 채널에 드래그 드랍하면 된다. 그러면 우측에 재생해서 볼 수 있는 상태가 된다.
이미지 140
영상 클립의 일부분만 사용하고 싶다면 타임라인에서 영상의 시작과 끝에 마우스를 가져가 보면 마우스 아이콘이 변견된다. 드래그 해서 원하는 만큼 시작과 끝을 지정해 주면 된다. 물론 중간에 영상을 칼로 잘라서 사용도 가능하다. 일단 이렇게 해서 원하는 부분을 지정해 주자. 다음 두번째 영상을 가져오자.
이미지 141
원하는 동영상과 이미지들을 순서대로 배치를 한다. 오디오가 포함된 비디오 클립인 경우 타임라인으로 가져 올때 키보드 shift를 누르면 오디오만 가져오고 alt키를 누르고 드래그 하면 비디오만 가져와 배치 할 수 있다. 이 예제에서는 영상에 포함된 오디오는 없애고 전체 배경음악을 넣을 것이기 때문에 영상에 포함된 오디오는 모두 제거 하였다. 이제 배경음악으로 사용할 오디오 파일을 드래그 해서 오디오 트랙에 배치하자.
이미지 142
이렇게 하면 비디오와 오디오를 모두 배치하여 편집이 끝이 났다. 이제 최종 결과물을 저장해 보자. 렌더링 한다고 한다.
이미지 143
렌더링 하기 위해서는 화면 맨 아래 로켓아이콘을 클릭하면 렌더링 화면으로 변경된다.
이미지 144
화면 좌측 상단에 보면 렌더링 설정을 변경할 수 있다. 주로 사용되는 포맷을 미리 제시된다. 유튜브를 선택하고 파일 이름과 저장위치, 비디오 오디오 포맷을 설정해 준다.  설정영역 아래에 있는 ‘Add to Render Queue’를 눌러서 렌더큐로 job을 등록한다. 이제 렌더링 하자. 렌더링 버튼은 화면 우측에 코딱지 만하게 잘 보이지도 않게 위치해 있다. 클릭하자. 렌더링이 끝이 나면 지정된 폴더에 최종 파일이 저장되게 된다.



일단 흐름은 이렇다. 제대로 할려면 영상 클립과 클립이 연결될때 전환효과 같은 것도 주고 자막도 넣고 시작할때 제목도 넣어 주고…해야 될것 같은데 다음에 알아 보기로 하자. 첫소감은 과분한 기능을 가지고 있는것 같다. 무비메이커는 비교가 안되네 … ^^; 앞으로 다양한 기능에 대해 알아가 보기로 하자.


화요일, 11월 27

자바스크립트와 CSS로 Carousel Slider 만들기

js_logo


jQuery를 이용하는 화려한 슬라이더 효과를 주는 라이브러리들이 많이 있다. 그런것 가져다가 사용하면 편할것 같지만 라이브러리 추가하고 설정을 해줘야 한다. 복잡하고 무겁다. 순수 자바스크립트(바닐라 자바스크립트)와 CSS만으로 간단한 슬라이더 효과를 만들어 보자. 세상.. 심플한것이 제일이다.

------------ index.html --------------

<!DOCTYPE html>
<html>
<head>
     <meta charset="utf-8">
     <title>Javascript Example</title>
     <style type="text/css">
         body{
             font-size: .8em;
             text-align: center;   
             margin: 0; padding: 0;
         }
         .slider{
             width: 100%;
             position: relative;
         }
         .slider_item{
             width: 100%;
             height: 500px;
             overflow: hidden;
             position: absolute;
             z-index: 0;
             opacity: 0;
             transition: all .7s ease-in-out;
             transform: scale(.8);
         }
         img {width: 100%;}

        .showing{
             opacity: 1;
             z-index: 1;
             transform: none;
         }
     </style>
</head>
<body>
     <h1>Javascript Example 001 - 자동 슬라이더</h1>
     <p>자바스크립트와 CSS만으로 Carousel Slider 효과를 구현해 봅니다. </p>

    <!-- Slider -->
     <div class="slider">
         <!-- items -->
         <div class="slider_item"><img src="img/sample01.jpg"></div>
         <div class="slider_item"><img src="img/sample02.jpg"></div>
         <div class="slider_item"><img src="img/sample03.jpg"></div>
         <div class="slider_item"><img src="img/sample04.jpg"></div>
         <div class="slider_item"><img src="img/sample05.jpg"></div>
     </div>

    <script type="text/javascript">
         const showing_class = "showing";
         const firstSlide = document.querySelector(".slider_item:first-child");
         function slide(){
             const currentSlide = document.querySelector(`.${showing_class}`); // showing 클래스가  있는 엘리먼트를 찾는다.
             if(currentSlide){
                 // 지금 shwoing 클래스를 가진 엘리먼트 다음 엘리먼트에 클래스를 추가 한다.
                 currentSlide.classList.remove(showing_class);
                 const nextSlide = currentSlide.nextElementSibling;
                 // 다음 엘리먼트가 있는지 없는지 체크 후 처리
                 if (nextSlide){
                     console.log(currentSlide);
                     nextSlide.classList.add(showing_class);
                 } else {//마지막이면(그다음 형제 엘리먼트가 없으니까) 첫 슬라이드에 추가 함.
                     firstSlide.classList.add(showing_class);
                 }

            } else { // showing 클래스가 지정된 엘리먼트가 없으면 첫번째에 추가해 준다.(페이지 시작시)
                 firstSlide.classList.add(showing_class);
             }
         }

        slide();
         setInterval(slide, 3000); // 1000은 1초
        
     </script>

</body>
</html>


----------------

데모페이지 : http://visualssing.dothome.co.kr/javascript/js_example001.html

월요일, 11월 26

파이썬 : 윈도우에서 pygame을 이용하여 게임 개발하기(2)–기본동작

이제 게임에 캐릭터를 등장 시켜서 몇가지 상황을 만들고 기본적인 동작을 하도록 수정해 주자. 게임패트 왼쪽 스틱으로 화면 아래쪽의 사각형을 x방향으로 만 왔다 갔다 움직이도록 하였다. 캐릭터가 아래로 빠져서 게임오버가 되지 않도록 위치를 잡아서 위로 튕켜 줘야 한다. 캐릭터는 자동으로 앞으로 점프를 하면서 이동하게 되어있다. 무기의 사용은 게임패드 우측의 A 버튼에 부여 하였다.
이미지 133
enemy들은 우측에서 무작위로 나오게 되어 있다. 이것들을 피하거나 제거해야 하는데 기능을 따로 주지 않았기 때문에 피할수는 없고 무기를 쐬서 제거를 해줘야 한다.  캐릭터도 스틱으로 움직히게 하면 되지만 예제는 예제니깐 간단히 하자.

-----------game.py--------------
import pygame
import random
import os
WIDTH = 800
HEIGHT = 480
FPS = 30
# Define colors
player1Color = (0, 180, 255)
player2Color = (180, 0, 180)
BGCOLOR = (255, 200, 0) #background color
WHITE = (255,255,255)
enemyColor = (0, 5, 255)
# set up assets folders
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "img")
# Player Class
class Player(pygame.sprite.Sprite):
     def __init__(self):
         pygame.sprite.Sprite.__init__(self)
         self.image = pygame.image.load(os.path.join(img_folder, "player1_1.png")).convert() # 이미지를 사용하는 경우
         self.image.set_colorkey(WHITE)
         self.rect = self.image.get_rect()
         self.rect.center = (WIDTH/2 - 100, HEIGHT - 50)
         self.y_speed = 3
    def update(self):
         self.rect.x += 3
         self.rect.y += self.y_speed
         if self.rect.bottom > HEIGHT:
             self.rect.y = 0
         if self.rect.top < 50:
             self.y_speed = 3
         if self.rect.left > WIDTH:
             self.rect.right = 0
        
         # 외곽를 지나면 처리
         if self.rect.left > WIDTH:
             self.rect.right = 0
         if self.rect.right < 0:
             self.rect.left = WIDTH
    def shoot(self):
         bullet = Bullet(player1.rect.x+25, player1.rect.y+25)
         bullet_sprites.add(bullet)
         all_sprites.add(bullet)

# Class
class Box(pygame.sprite.Sprite):
     def __init__(self):
         pygame.sprite.Sprite.__init__(self)
         self.image = pygame.Surface((60, 20)) # 도형을 사용하는 경우
         self.image.fill(player2Color)
         self.rect = self.image.get_rect()
         self.rect.center = (WIDTH/2, HEIGHT - 45)
         self.x_speed = 0
    def update(self):
         self.rect.x  += self.x_speed
         # 스틱을 움직이면
         if event.type == pygame.JOYAXISMOTION:
             self.x_speed  += gamepads[-1].get_axis(0) *1
             if self.x_speed > 10:
                 self.x_speed = 10
             # self.rect.y += gamepads[-1].get_axis(1) *4
         if self.rect.left > WIDTH:
             self.rect.right = 0
         if self.rect.right < 0:
             self.rect.left = WIDTH
# Enemy Class
class Enemy(pygame.sprite.Sprite):
     def __init__(self):
         pygame.sprite.Sprite.__init__(self)
         self.image = pygame.Surface((30, 30)) # 도형을 사용하는 경우
         self.image.fill(enemyColor)
         self.rect = self.image.get_rect()
         self.rect.center = (random.randrange(WIDTH, WIDTH *2), random.randrange(50, HEIGHT - 50))
         self.x_speed = random.randrange(-5, -1)
    def update(self):
         self.rect.x += self.x_speed
         if (self.rect.right < 0):
             self.rect.left = WIDTH
             self.rect.top = random.randrange(100, 300)
# bullets
class Bullet(pygame.sprite.Sprite):
     def __init__(self, x, y):
         pygame.sprite.Sprite.__init__(self)
         self.image = pygame.Surface((10, 3)) # 도형을 사용하는 경우
         self.image.fill(player2Color)
         self.rect = self.image.get_rect()
         self.rect.center = (x,y)
         self.x_speed = 20
    def update(self):
         self.rect.x += self.x_speed
         if self.rect.left > WIDTH:
             self.kill() # 오호 이거 편하네 .

# initialize
pygame.init()
pygame.mixer.init() #for sound
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Jumper')
clock = pygame.time.Clock()
width, height = pygame.display.get_surface().get_size()
lead_x = width/2 -100
lead_y = height - 100
lead2_x = width/2 + 100
lead2_y = height - 100
#연결된 모든 디바이스 배열에 추가
gamepads = []
for i in range(0, pygame.joystick.get_count()):
     gamepads.append(pygame.joystick.Joystick(i))
     gamepads[-1].init()
# set up sprites
all_sprites = pygame.sprite.Group()
player_sprites = pygame.sprite.Group()
bullet_sprites = pygame.sprite.Group()
enemy_sprites = pygame.sprite.Group()
player1 = Player()
player_sprites.add(player1)
box_sprites = pygame.sprite.Group()
box = Box()
box_sprites.add(box)
# for문
for i in range(10):
     enemy = Enemy()
     enemy_sprites.add(enemy)
     all_sprites.add(enemy)
all_sprites.add(player1)
all_sprites.add(box)
# print(all_sprites)

#Game Loop
running = True
while running:
     clock.tick(FPS)
     # process input(events)
     for event  in pygame.event.get():
         if event.type == pygame.QUIT:
             running = False
     # 버튼을 누르면
     if event.type == pygame.JOYBUTTONDOWN :
         if event.button == 0:
             player1.shoot()
    # update
     all_sprites.update()
    hits = pygame.sprite.groupcollide(enemy_sprites, bullet_sprites, True, True)
     if hits:
         # 새로운 enemy를 추가해 줌
         enemy = Enemy()
         enemy_sprites.add(enemy)
         all_sprites.add(enemy)
    # 충돌감지
     hit = pygame.sprite.spritecollide(player1, box_sprites, False)
     if hit:
         player1.y_speed *= -1
    # draw / render
     screen.fill(BGCOLOR)
     all_sprites.draw(screen)
     pygame.display.update() # or flip()
pygame.quit()
quit()
-----------------
각각의 요소들은 클래스를 이용해서 생성하고 sprite 그룹에 등록해서 관리를 편하게 해준다. 충돌 감지등을 할때 편리하다.  각각의 스프라이트 클래스에 원하는대로 동작이나 모양을 지정해 주면 된다.


파이썬 : 윈도우에서 pygame을 이용하여 게임 개발하기(1)

윈도우에서 파이썬으로 간단한 게임을 개발해 보기로 하자. 이전에 해 본것 같은데 복습이 될듯 하다. pygame을 사용하기 위해서 먼저 설치를 해줘야 한다.
python -m pip install -U pygame –user
먼저 게임패드를 파이썬에서 어떻게 읽어 들릴까? 자바스크립트에서 끙끙대며 겨우 알아 냈었는데 파이썬도 마찬가지로 겨우 알아 냈다. 필요한 버튼만 찾아 내자. 나머지 버튼은 동일한 방식으로 활용하면 된다. 먼저 간단히 게임패드로 화면의 박스를 움직이는 예제를 만들어 보자.  좌, 우 스틱을 이용해서 박스를 움직이도록 했다. 전면의 L1과 R1에는 슈팅기능이나 기타 기능을 연결해 주면 될듯 하다. 예제에서는 색상이 변하도록 했다.  양손으로 오브젝트를 따로 따로 움직이는게 쉬운게 아니구나..ㅋ
이미지 131
유아틱한 색상 좋아. 파이썬 코드를 살펴 보자.
------------- game.py----------
import pygame
pygame.init()
playerColor1 = (0, 180, 255)
playerColor2 = (180, 0, 180)
bgColor = (255, 200, 0) #background color
gameDisplay = pygame.display.set_mode((640, 480))
pygame.display.set_caption('Control')
pygame.display.update()
gameExit = False
lead_x = 200
lead_y = 300
lead2_x = 400
lead2_y = 300
gamepads = []
clock = pygame.time.Clock()

width, height = pygame.display.get_surface().get_size()
font = pygame.font.SysFont("comicsansms", 42)
basicfont = pygame.font.SysFont(None, 22)
text = font.render("Hello Pygame", True, (0, 128, 0))
stick1 = font.render("L", True, (0, 0, 0))
stick2 = font.render("R", True, (0, 0, 0))
basicText = basicfont.render('<info>', True, (0, 0, 0))

for i in range(0, pygame.joystick.get_count()):
     gamepads.append(pygame.joystick.Joystick(i))#연결된 모든 디바이스 배열에 추가
     gamepads[-1].init()
     gamepadInfo = basicfont.render("Detected joystics: " + gamepads[-1].get_name(), True, (0,0,0))
     gamepadInfo2 = basicfont.render("Button: " + str(gamepads[-1].get_numbuttons()), True, (0,0,0))
     gamepadInfo3 = basicfont.render("Stick: " + str(gamepads[-1].get_numaxes()), True, (0,0,0))

while not gameExit:
     clock.tick(60)
    
     for event in pygame.event.get():
         if event.type == pygame.QUIT:
             gameExit = True
    # 버튼을 누르면
     if event.type == pygame.JOYBUTTONDOWN :
         if event.button == 4:
             playerColor1 = (255, 0, 0)
         if event.button == 5:
             playerColor2 = (255, 0, 0)
     else:
         playerColor1 = (0, 180, 255)
         playerColor2 = (180, 0, 180)

    # 스틱을 움직이면
     if event.type == pygame.JOYAXISMOTION:
         lead_x += gamepads[-1].get_axis(0) *4
         lead_y += gamepads[-1].get_axis(1) *4
         lead2_x += gamepads[-1].get_axis(4) *4 #뭐지 이 얼척없는 번호의 순서는?
         lead2_y += gamepads[-1].get_axis(3) *4
        #
        # 외곽을 벗어 나면
         if(lead_x > width):
             lead_x = 0
         elif(lead_x < 0):
             lead_x = width
         elif(lead_y > height):
             lead_y = 0
         elif(lead_y < 0):
             lead_y = height
        if(lead2_x > width):
             lead2_x = 0
         elif(lead2_x < 0):
             lead2_x = width
         elif(lead2_y > height):
             lead2_y = 0
         elif(lead2_y < 0):
             lead2_y = height
    # 화면에 그리기
     gameDisplay.fill(bgColor)
     pygame.draw.rect(gameDisplay, playerColor1, [lead_x, lead_y, 40, 40])
     pygame.draw.rect(gameDisplay, playerColor2, [lead2_x, lead2_y, 40, 40])
     gameDisplay.blit(stick1, (lead_x+10, lead_y-20))
     gameDisplay.blit(stick2, (lead2_x+10, lead2_y-20))
     gameDisplay.blit(text, (320 - text.get_width() // 2, 80 - text.get_height() // 2))
     gameDisplay.blit(basicText, (10, 20))
     gameDisplay.blit(gamepadInfo, (10, 40))
     gameDisplay.blit(gamepadInfo2, (10, 60))
     gameDisplay.blit(gamepadInfo3, (10, 80))
     pygame.display.update()
pygame.quit()
quit()
-------------
파이썬3으로 실행하면 된다. 이젠 기본이 파이썬3이다. 파이썬2? 그런게 있는지 난 모른다. 신경 안쓴다. ^^;
파이썬에서 게임패드 사용에 대한 자세한 내용은 아래 링크를 참조 하자.
https://www.pygame.org/docs/ref/joystick.html


토요일, 11월 24

P5.js : 우주 슈팅게임(5)–게임패드 연결

asteroid-1477065_1280
사실 지금까지 해 왔던게 바로 이 게임패드를 연결해 보려고 했던것이었다.  게임패드 용도에 맞게 하나의 게임이 필요해서 P5.js로 만드는 게임을 지금 까지 해 봤던 것이다. 최신 웹 브라우저에서는 게임패드를 인식하고 사용할 수 있도록 기본으로 되어 있는데, 물론 브라우저마다 안되거나 약간 다른 용법을 사용한것 같기도 하다. 아직 지원하지 않기도 하는 모양이다. 여기서는 윈도우10에서 크롬브라우저를 기준으로 예제를 만들었다. 다른 환경에서 테스트는 해 보지 않았다.  제일 먼저 html 문서를 보자.
-------------------index.html-----------------
<!doctype html>
<html lang="ko">
  <head>
   <meta name="viewport" content="width=device-width, user-scalable=no">
   <meta charset="UTF-8">
   <meta name="Description" content="">
   <title>P5.JS 연습</title>
   <link href="https://fonts.googleapis.com/css?family=Orbitron" rel="stylesheet">
   <style type="text/css">
        body{
       text-align: center;
       margin: 0px;
       padding: 0px;
     }
      p{
       font-size: .8em;
      }
      #defaultCanvas0{
     }
   </style>
   <!--공통-->
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.sound.min.js"></script>
   <!--프로젝트 스크립트-->
   <script src="sketch19-final.js"></script>
   <script src="ship3.js"></script>
   <script src="asteroid.js"></script>
   <script src="laser.js"></script>
   <script src="particle2.js"></script>
   <script src="explode.js"></script>
   <script src="firework.js"></script>
</head>
  <body>
   <h1>P5.js Example 19-final(Simple Game)</h1>
   <audio autoplay controls preload="auto" loop  id="myAudio">
      <source src="http://soundimage.org/wp-content/uploads/2014/04/Game-Menu.mp3">
      Your browser does not support the audio element. 
  </audio>
  <p>게임패드 이동: 왼편 스틱, 슈팅: 오른쪽 R2,  재시작 : F5, BGM : Music by Eric Matyas www.soundimage.org</p>
  
  </body>
</html>
---------------------------------------------
필요한 자바스크립들은 별도의 파일로 만들고 링크해서 사용하도록 하였다. 이문서는 간단하다.
-----------------sketch.js-----------------
var ship;
var asteroids = [];
var lasers = [];
var font, fontsize = 15;
var health = 100;
var shoot;
var bomb;
let particles = [];//var와 let의 차이를 모르겠음? let이 더 엄격하다 정도만.
var fireworks = [];
function preload(){
     shoot = loadSound('sound/laser_shoot.mp3');
     bomb = loadSound('sound/bom.wav');
}

function setup() {
     createCanvas(800, 480);
     //createCanvas(windowWidth,windowHeight);
     font="Orbitron";
     textFont(font);
     textSize(fontsize);
     //우주선 생성
     ship = new Ship();
     //소행성 생성
     for(let i =0; i < 10; i++){
         asteroids.push(new Asteroid());
     }
}
function draw() {
     background(0);
    // Gamepad
     pads = navigator.getGamepads();
     pad0 = pads[0];
    if(pad0){
         // 오른쪽 R2 버튼(앞면 큰 버튼)
         if (pad0.buttons[7].value > 0.6 && pad0.buttons[7].pressed == true){
             lasers.push(new Laser(ship.pos, ship.heading));//너무 연속적으로 추가 되는 문제
             shoot.play();
         }
         // 스틱
         if(pad0.axes[0] >= .5 ){
             ship.boosting(true);
         } else if(pad0.axes[0] <= -.5) {
             ship.boosting(true);
         } else if (pad0.axes[1] < -.5){
             ship.boosting(true);
         } else if (pad0.axes[1] > .5){
             ship.boosting(true);
         }
     }
    ship.c = color(100, 255, 100,  255);
     // Backgroud Particle
     let p = new Particle();
     particles.push(p);//draw()에 동작해서 계속해서 객체를 만들어 추가한다.
     for(let i = particles.length-1; i >= 0; i--){
         particles[i].update();
         particles[i].show();
         if(particles[i].finished()){
             particles.splice(i, 1);
         }
     }
    
     // Explosion
     for(var i = 0; i < fireworks.length; i++){
         fireworks[i].run();   
         if(fireworks.length>10){
             fireworks.splice(0, 1);
         }
     }
    //소행성
     for (var i = 0; i < asteroids.length; i++){
         //소행성과 우주선이 충돌하면
         if(ship.hits(asteroids[i])){
             //console.log("hit");
             ship.c = color(255, 0, 0,  255);
             health = health - asteroids[i].r * 0.05;
         }
        asteroids[i].update();
         asteroids[i].render();
         asteroids[i].edges();
     }
    // 레이저
     for (var i = lasers.length -1; i >= 0; i--){
         lasers[i].update();
         lasers[i].render();
         // 화면을 벗어나면 제거 해줌
         if(lasers[i].offscreen()){
             lasers.splice(i, 1);
         } else {
             // 충돌 감지
             for(var j = asteroids.length-1; j >= 0; j--){
                 if(lasers[i].hits(asteroids[j])){
                     //console.log('hit');
                     health = health + asteroids[j].r * 0.1;
                     if(asteroids[j].r > 10) {
                             var newAsteroids = asteroids[j].breakup();// 충돌된 소행성을 쪼갠다.
                             asteroids = asteroids.concat(newAsteroids);
                     }
                     fireworks.push(new Firework(lasers[i].pos.x, lasers[i].pos.y));
                     asteroids.splice(j, 1); //j번째 1개를 제거한다.
                     lasers.splice(i, 1);
                     bomb.play();
                    break;
                 }
             }
        }
     }
    // 우주선
     ship.render();
     ship.turn();
     ship.update();
     ship.edges();
    // Score
     drawScore();
}
// Score and Health
function drawScore(){
     fill(255);
     if(health <= 0){
         text("Game Over", 30, 30);
     } else {
         text(Math.ceil(health), 30, 30);
     }
     if (asteroids.length <= 0){
         text("You Win", 30, 50);   
     }
}
----------------------------
메인 스케치 파일이다. 키보드 조작기능은 제거를 했다. 게임패드와 키보드 조작을 다 같이 사용하게 할려면 설정 코드가 더 필요한데 귀찮다. 원래 목적대로 게임패드만 사용하게 해 주자.  이 메인 스케치 이외에 우주선, 소행성, 레이저, 폭발효과를 위한 객체 클래스들이 필요하다. 이걸 다 일일히 여기 적기는 힘들고 자바스크립트 이니 소스가 다 보인다. 찾아서 참고 하면 될듯 하다. ^^;
기본 게임 만드는 유튜브로 만든 것에 필요한 기능 몇가지를 추가해 준것이다. 사운드 효과를 주면 더 게임 다워 진다.
이미지 130
게임패드의 왼쪽 조이스틱(맞나 용어가?)를 이용해서 우주선을 움직이게 하는데 이게 키보드 이동키로 단순히 회전하고 전진하고 하는 것과는 좀 다르게 해 줄 필요가 있었다. 상하좌우 아무곳으로나 이동이 가능하게 해주고 해당 방향으로 움직이면 그 방향으로 우주선 헤드가 돌아 가도록 해줘야 했다. 이것을 구현하는게 난감하게 생각되었는데 의외로 간단히 구현 할 수 있었다.
---------------ship.js-------------------
this.turn = function(){
         //this.heading += this.rotation;
         this.heading  = this.vel.heading();
     }
--------------------------------------------
vel 벡터의 heading() 을 적용하니 쉽게 구현이 되었다. 좋아~  스틱의 움직임에 따라 우주선이 자유롭게 조정이 가능했다. 정밀하게 제어하기는 힘들지만 이정도면 충분해 보인다.  마지막 최종 결과는 아래 링크에서 확인해 보자. 물론 호환이 되는 기본형 게임패드가 있어야 게임이 가능하다. 없는 사람에게는 아무것도 해 볼 수 업다. ^^; 데모 영상은 차후 만들어서 추가해 볼 예정이다.

http://visualssing.dothome.co.kr/p5js/p5js_exam19-final.html


자바스크립트와 P5.js에서 게임패드 사용하기

일전에 뷰잉에서 게임이나 가끔 해볼까 하고 게임패드를 하나 구입했었다. 이 게임패드를 크롬 브라우저에서 자바스트립트를 이용해서 활용해 보기로 하자. 먼저 간단히 게임패드들의 버튼들을 인식하는 예제를 만들어 보자.

20181120_191657


<!doctype html>
<html lang="ko">
  <head>
   <meta name="viewport" content="width=device-width, user-scalable=no">
   <meta charset="UTF-8">
   <meta name="Description" content="">
   <title>P5.JS 연습</title>
   <style type="text/css">
        body{
       text-align: center;
     }
      p{
       font-size: .9em;
      }
      #defaultCanvas0{

     }

     #screen{
       width: 80px;
       height: 80px;
       margin: 0 auto;
       position: relative;
      }

     #ball {
         width: 80px;
         height: 80px;
         border-radius: 40px;
         background-color: red;
         position: relative;
         line-height: 75px;
         text-align: center;
         font-size: 40px;
       }
   </style>
   <!--공통-->
   <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script> -->
   <!--프로젝트 스크립트-->
   <!-- <script src="sketch21.js"></script>
   <script src="gamepad.js"></script> -->
  </head>
  <body>
   <h1>P5.js Example 21</h1>
   <p id="gamepad-info">Waiting for Gamepad.</p>
   <div id="screen">
     <div id="ball"></div>
   </div>

  <script type="text/javascript">
     var gamepadInfo = document.getElementById("gamepad-info");
     var ball = document.getElementById("ball");
     // pos
     var a = 0;
     var b = 0;
     var start;
     var text = "";

    // webkitRequestAnimationFrame
     var rAF = window.mozRequestAnimationFrame ||
         window.webkitRequestAnimationFrame ||
         window.requestAnimationFrame;

    var rAFStop = window.mozCancelRequestAnimationFrame ||
       window.webkitCancelRequestAnimationFrame ||
       window.cancelRequestAnimationFrame;

    // Check connection
     window.addEventListener("gamepadconnected", function(e) {
       var gp = navigator.getGamepads()[e.gamepad.index];
           gamepadInfo.innerHTML = "Gamepad connected at index "+gp.index+": "+gp.id+", "+gp.buttons.length+" buttons, "+gp.axes.length+" axes";
    
       gameLoop();
     });

    // Check disconnection
     window.addEventListener("gamepaddisconnected", function() {
       gamepadInfo.innerHTML = "Waiting for gamepad.";

      //rAFStop(start);
     });

    function gameLoop() {
       if(navigator.webkitGetGamepads) {//이게 아니다.
         console.log(webkitGetGamepads);
       } else {
         var gp = navigator.getGamepads()[0];


         if(gp.axes[0] !=0 || gp.axes[1] != 0){
           a += gp.axes[0];
           b += gp.axes[1];
           text= "Ax";
         }

        if(gp.buttons[0].value > 0 || gp.buttons[0].pressed == true) {//A button
           text = "A";
         } else if(gp.buttons[1].value > 0 || gp.buttons[1].pressed == true) {//B button
           text = "B";
         } else if(gp.buttons[2].value > 0 || gp.buttons[2].pressed == true) {//X button
           text = "X";
         } else if(gp.buttons[3].value > 0 || gp.buttons[3].pressed == true) {//Y button
             text = "Y";
         }

      }

      ball.style.left = a*4 + "px";
       ball.style.top = b*4 + "px";
       ball.innerHTML = text;

      var start = rAF(gameLoop);
     };

  </script>
  
  </body>
</html>

간단히 div 로 만든 빨간 써클을 게임패드로 움직일 수 있는 예제이다.

이미지 127

왼편 조이스틱과 오른쪽 버튼들에게 기능을 지정해 주었다. 두번째 예제는 p5.js안에서 직접 코드를 작성하는 예제도 만들어 보자. 게임패드 각각의 버튼들의 값들을 출력해 주는 예제이다.


var pads, pad0;

function setup(){
     createCanvas(640, 480);
     textSize(14);
     stroke(80);
     strokeWeight(.3);
}

function draw(){
     background(0);
     fill(255);

    pads = navigator.getGamepads();
     pad0 = pads[0];
    
     text('ID: ', 10, 20);
     if(pad0){
         //console.log(pad0.buttons.length);
         text(pad0.id, 35, 20)
         text('-----', 15, 40);
         for(var i =0; i < pad0.buttons.length; i++){
             text('Button'+i+': ' + pad0.buttons[i].value, 15, 60 + 20 * i);
             //console.log(pad0.buttons.length);
         }text('-----', width/2, 40);
         for (var i = 0; i < pad0.axes.length; i++) {
             text('axes' + i + ': ' + pad0.axes[i], width/2, 60 + 20 * i);
         }
     }
}

이미지 128

연결된 게이패드의 버튼과 조이스틱을 움직여 보면 값들이 변하는 것을 확인 할 수 있다. 대부분의 버튼은 0과 1이다. 조이스틱은 –1에서 1사이의 값을 가진다. 이렇게 게임패드의 버튼들의 값이 p5.js로 전달 되었으니 이것을 이용해서 화면안에서 사용할 수 있게 된다.



금요일, 11월 23

프로세싱(115) : P5.js 파티클시스템의 예제

곁다리… 앞서 만든 게임에서 폭파효과를 주기 위해 필요해서 따로 예제를 만들어 보았다.

<!doctype html>
<html lang="ko">
  <head>
   <meta name="viewport" content="width=device-width, user-scalable=no">
   <meta charset="UTF-8">
   <meta name="Description" content="">
   <title>P5.JS 연습</title>
   <style type="text/css">
        body{overflow-x : hidden; overflow-y: hidden; text-align: center;}
      p{
       font-size: .9em;
      }
      #defaultCanvas0{

     }
   </style>
   <!--공통-->
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>
   <!--프로젝트 스크립트-->
   <script src="sketch20.js"></script>
   <script src="explode.js"></script>
   <script src="firework.js"></script>
  </head>
  <body>
   <h1>P5.js Example 20(Particle system)</h1>
   <p>마우스를 클릭하세요</p>
  
  </body>
</html>

마우스를 클릭하면 사방으로 퍼지는 파티클이 생성되었다가 사라진다.

var fireworks = []; //array

function setup(){
     createCanvas(640, 480);
}

function draw(){
     background(0);

    for(var i = 0; i < fireworks.length; i++){
         fireworks[i].run();   
         if(fireworks.length>10){
             fireworks.splice(0, 1);
         }
     }
}

// 마우스를 클릭하면 새로운 파티클을 firewroks array에 추가한다.
function mousePressed() {
   fireworks.push(new Firework(mouseX, mouseY));
}

이중구조 배열에 파티클을 담는다.

function Particle(x, y){
     this.pos = createVector(x, y);
     this.vel = createVector(random(-2, 2), random(-2, 2));
     this.acc = createVector(0,0);
     this.alpha = 255;

    this.finished = function(){
         return this.alpha < 0;
     }

    // 중력을 주고 싶으면 사용
     this.applyForce = function(force){
         this.acc.add(force);
     }

    this.update = function(){
         this.vel.add(this.acc);
         this.pos.add(this.vel);
         this.acc.mult(0);
         this.alpha -= 6;
     }

    this.show = function(){
         stroke(255, this.alpha);
         strokeWeight(2);
         point(this.pos.x, this.pos.y);
     }
}


그 결과는 아래 링크에서 확인 하자.

http://visualssing.dothome.co.kr/p5js/p5js_exam20.html

프로세싱(114) : P5.js 우주 슈팅 게임(3)

asteroid-1477065_1280

이제 게임에 사운드와 몇가지 효과를 추가하자.  P5.js에서 사운드를 사용하기 위해서는 오디오 관련 라이브러리를 사용해야 한다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.sound.min.js"></script>

이미지 126


배경에 파티클을 이용해서 저 멀리 별들도 그려 주자. 우주공간이 이잖아. 사운드 이펙트는 레이저빔 소리와 행성 쪼개지는 소리(이건 별로 마음에 안듬)를 넣어 주었다. 핼쓰(스코어)  수치도 넣어 주었다. 이제 더이상 할게 없다. ^^; 최종 결과는 아래 링크에서 확인 하자.

http://visualssing.dothome.co.kr/p5js/p5js_exam19-3.html

목요일, 11월 22

프로세싱(113) : P5.js 우주 슈팅 게임(2)

asteroid-1477065_1280

이제 떠돌아 다니는 소행성들을 만들어 주자. 마찬가지로 아래 유튜브 영상을 따라가자.

https://youtu.be/hacZU523FyM

  • 다수의 asteroid를 만들어 줘야 한다. 모양도 제각각이다. Asteroid 클스를 이용하여 원하는 갯수만큼 만들어 주면 된다.  여러가지 모양은 vertex를 이용해서 꼭지점의 위치에 무작위 변화를 주어 다른 모양으로 그려 준다. 기본적인 동작은 동일하다. 화면을 벗어 나면 반대편에서 다시 나오게 되어 있다.

http://visualssing.dothome.co.kr/p5js/p5js_exam19-1.html

이제 우주선에서 레이저가 발사 되게 만들어 주고 소행성들에 레이저가 맞게 되면 소행성이 둘로 쪼개지도록 해준다.  지정한 크기의 행성을 맞추면 완전히 제걱 된다. 자세한 내용는 아래 유트브를 따라 가자.

https://youtu.be/xTTuih7P0c0

이미지 125

이제 어느정도 게임이 기본 형태를 갖췄다. 필요하다면 점수판을 넣어 주고 오디오 효과도 넣어 주도록 하자.  최종 결과는 아래 링크로 확인 하자.

http://visualssing.dothome.co.kr/p5js/p5js_exam19-2.html

프로세싱(112) : P5.js 우주 슈팅 게임(1)

asteroid-1477065_1280

P5.js를 이용하여 게임을 만드는 유튜브 동영상을 따라서 간단히(?) 게임을 하나 만들어 보자. 코드를 작성하는게 중요한게 아니고 코드의 의미를 이해하는 것이 더 중요하다. 제일 먼저 우주선 클래스를 만들고 플레이어가 될 우주선을 하나 만들어 키보드에 따라 움직이도록 하는 작업을 하자. 자세한 내용은 아래 링크이 동영상을 참조 하자. 게임의 목표는 떠 돌아 다니는 소행성을 모두 제거하면 된다.

https://youtu.be/hacZU523FyM

이거 하나 움직이는데도 코드가 복잡하다. 최종 결과물은 실제 우주공간에 떠 있는 것처럼 끊어 지지 않고 유영하듯이 잘 움직이다. 화살표 키보드에 의해 동작된다. 좌, 우키로 방향을 전환하고 업키로는 우주선을 전진하게 한다.

1차 결과는 아래 링크에서 확인하자. 따라 한거라서 별 쓸 내용이 없다 ^^;

http://visualssing.dothome.co.kr/p5js/p5js_exam19.html

이제 소행성들을 만들어 주자.

다음편에 계속 …

화요일, 11월 20

크롬 브라우저에서 음성인식 SpeechRecognition API 구현(2)

파트1에 이어서 이번에는 좀 더 기능을 추가해 보기로 하자. 앞서 크롬 브라우저에서 음성을 인식하고 텍스트를 화면에 출력해 주는 것 까지 구현이 되었다. 여기다 한글 텍스트를 영문으로 번역하고 그 결과를 음성으로 읽어 주는 기능을 추가하자. 번역 API를 찾아 보니 몇가지 대안이 있는데 강력한 후보이 구글번역 API가 유료로 전환된듯 결제설정을 하라고 나온다. 이런…

  • 구글 Translate API
  • Microsoft Azure Translate API
  • Yandex

구글은 유료(정확하지 않음)이고 마이크로소프트는 12개월 무료인데 그후엔 유료라고 한다. 결국 선택한것은 Yadex라는 API 서비스이다. 그런데 문제는 번역 품질이 시원찮다. 일단 흐름을 파악하기 위해서 이것을 이용해 보기로 하자.


https://tech.yandex.com/translate/


위 링크에서 회원가입을 하고  API 키를 발급 받아야 한다.


function translate_yandex(txt){
             var url = "https://translate.yandex.net/api/v1.5/tr.json/translate",
             keyAPI = "your_yandex_api_key";

            var xhr = new XMLHttpRequest(),
             textAPI = txt;
             langAPI = "en";

        //     https://translate.yandex.net/api/v1.5/tr.json/translate
                  // ? key=<API key>
                  // & text=<text to translate>
                  // & lang=<translation direction>
                  // & [format=<text format>]
                  // & [options=<translation options>]
                  // & [callback=<name of the callback function>]

            data = "key="+keyAPI+"&text="+textAPI+"&lang="+langAPI;
             xhr.open("POST",url,true);
             xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
             xhr.send(data);
             xhr.onreadystatechange = function() {
                 if (this.readyState==4 && this.status==200) {
                     var res = this.responseText;
                     console.log(res);
                     //document.querySelector('#json').innerHTML = res;
                     var json = JSON.parse(res);
                     if(json.code == 200) {
                         console.log(json.text[0]);
                         english.innerHTML = json.text[0];
                         text_to_speech(json.text[0]);

                    }
                     else {
                         console.log("Error Code: " + json.code);
                         //document.querySelector('#output').innerHTML = "Error Code: " + json.code;
                     }
                 }
             }
         }


함수를 추가하자. 앞 파트1에서 나온 음성인식 결과를 인자로 넣어서 호출해 주면 된다.


데모링크 : https://timbuktu031.github.io/voice_recogintion/


translate-3796096_640

뷰잉(안드로이드 TV박스)를 위한 안드로이드 게임패드 구입

뷰잉도 안드로이드TV박스이니 안드로이드 게임이 제한적으로 가능하다. 가끔 해볼려고 했더니 리모콘으로 제대로 하기는 힘들어 보인다. 그래서 게임패드(정확히 이름이 뭐지? 조정기?)를 저렴한것으로 하나 구입했다. 알리익스프레스에서 11.11 광군절에 쬐금 할일할때 구입했던게 이제 도착했다. 얼마였더라 $10 정도 였던것 같다.
20181120_185250
부피 때문에 박스는 없고 에어비닐에 나름 안전하게 포장되어 도착했다.  우체부 아저씨가 편지함에 넣고 가는 배송으로 도착했다. 분실없이 잘 도착했다.
20181120_185411
구성품은 조정기 본체랑 스마트폰 홀더, USB 리시버, 폰용 OTG 가 들어 있다.
20181120_185430 각부 명칭.
20181120_185605
안드로이드 TV인 뷰잉에 연결하기 위해서는 USB 리시버만 있으면 된다. 연결하자.
20181120_185631
조정기 아래쪽에 AAA사이즈 건전지 두개로 전원을 공급한다.
20181120_191657
리시버를 연결하면 자동으로 인식이 되니 특별히 설정할 것은 없다. 게임 하나 실행해 보니 정상적으로 작동이 되는것 같다. 버튼은 많은데 다 동작하는것은 아닌것 같다. 게임의 종류에 따라 작동되는 버튼이 따로 있는 모양이다.
https://youtu.be/kGaB755YzeE


월요일, 11월 19

크롬 브라우저에서 음성인식 SpeechRecognition API 구현

이것은 현재 구글 크롬 브라우저에서만 가능한것 같다. 다른 브라우저(파이어폭스, 익스플로러)에서는 되지 않는다. 간단히 예제를 만들어 보자.

이미지 124

페이지에 접속하면 이런 화면이다. Start버튼을 누르면 SpeechRecognition 을 음성인식이 시작된다. 인식된 데이터를 왼쪽 필드에 출력해 준다. 이어서 speechSynthesis 를 이용해서 음성으로 출력해 주게 된다.  일단 여기 까지만 구현해 보자.


<!DOCTYPE html>
<html>
<head>
     <meta charset="utf-8">
     <title>Speech to Text</title>
     <style>
         body{
             text-align: center;
         }

        button{
             padding: 8px;
             /*border-radius: 6px;*/
         }
         #message {
             color: #996600;
         }

        .textWrapper{
             width: 800px;
             margin: 0 auto;
             display: flex;
             flex-direction: row;
         }
         .textbox{
             height: 100px;
             border: 1px solid #d3d3d3;
             flex: 1;
             margin : 5px 15px;
             border-radius: 6px;
             text-align: left;
             padding: 16px;
         }
     </style>
     <!-- <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script> -->
     <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/annyang/2.6.0/annyang.min.js"></script> -->
</head>
<body>

    <h1>Speech to Text Example!!!</h1>

    <button id="speech" onclick="speech_to_text()">Start STT</button>
     <button id="stop" onclick="stop()">Stop</button>
     <p id="message">버튼을 누르고 아무말이나 하세요.</p>

    <div class="textWrapper">
         <div id="korea" class="textbox"></div>
         <div id="english" class="textbox"></div>
     </div>

    <script type="text/javascript">

        var message = document.querySelector("#message");
         var button = document.querySelector("#speech");
         var korea = document.querySelector("#korea");
         var english = document.querySelector("#english");
         var isRecognizing = false;

        if ('SpeechRecognition' in window) {
           // Speech recognition support. Talk to your apps!
           console.log("음성인식을 지원하는 브라우저입니다.")
         }

        try {
             var recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition)();
         } catch(e){
             console.error(e);
         }

        recognition.lang = 'ko-KR'; //선택하게 해줘야 할듯 .
         recognition.interimResults = false;
         recognition.maxAlternatives = 5;
         //recognition.continuous = true;


         function speech_to_text(){
            
             recognition.start();
             isRecognizing = true;

            recognition.onstart = function(){
                 console.log("음성인식이 시작 되었습니다. 이제 마이크에 무슨 말이든 하세요.")
                 message.innerHTML = "음성인식 시작...";
                 button.innerHTML = "Listening...";
                 button.disabled = true;
             }
            

            recognition.onspeechend = function(){
                 message.innerHTML = "버튼을 누르고 아무말이나 하세요.";
                 button.disabled = false;
                 button.innerHTML = "Start STT";
             }

            recognition.onresult = function(event) {
                 console.log('You said: ', event.results[0][0].transcript);
                 // 결과를 출력
                 var resText = event.results[0][0].transcript;
                 korea.innerHTML = resText;

                //text to sppech
                 text_to_speech(resText);
                
             };

            recognition.onend = function(){
                 message.innerHTML = "버튼을 누르고 아무말이나 하세요.";
                 button.disabled = false;
                 button.innerHTML = "Start STT";
                 isRecognizing = false;

            }
         }

        function stop(){
             recognition.stop();
             message.innerHTML = "버튼을 누르고 아무말이나 하세요.";
             button.disabled = false;
             button.innerHTML = "Start STT";
             isRecognizing = false;
         }


        // Text to speech
         function text_to_speech(txt){
             // Web Speech API - speech synthesis
             if ('speechSynthesis' in window) {
              // Synthesis support. Make your web apps talk!
                  console.log("음성합성을 지원하는  브라우저입니다.");
             }
             var msg = new SpeechSynthesisUtterance();
             var voices = window.speechSynthesis.getVoices();
             //msg.voice = voices[10]; // 두번째 부터 완전 외국인 발음이 됨. 사용하지 말것.
             msg.voiceURI = 'native';
             msg.volume = 1; // 0 to 1
             msg.rate = 1.3; // 0.1 to 10
             //msg.pitch = 2; //0 to 2
             msg.text = txt;
             msg.lang = 'ko-KR';

            msg.onend = function(e) {
                 if(isRecognizing == false){
                     recognition.start();   
                 }
                   console.log('Finished in ' + event.elapsedTime + ' seconds.');
             };
             window.speechSynthesis.speak(msg);
         }

    </script>

</body>
</html>


전체 코드인데 제대로 된건지는 아직 모르겠다. 일단 작동은 하니깐. 여러가지 메소드들이 있는데 정확한 사용법은 앞으로  예제를 더 만들어 보면서 바로 잡도로 하자. 예제는 단순히 앞 음성인식이 끝이 나면 자도으로 다시 음성인식을 시작하도록 하였다. 다른 방법도 있을것 같은데 …  자세한 내용은 아래 사이트를 참조 하자.


https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition


앞으로 계획은 한글로 인식된 음성을 gTTS를 이용해서 영어로 번역해서 음성으로 출력하게 하면 된다. 자동 영어 번역기 ㅋㅋ  한글-> 영어 혹은 영어 –> 한글을 옵션으로 선택하게 해주는 버튼도 추가를 해줘야 할것 같다.


데모 사이트 : https://timbuktu031.github.io/voice_recogintion/

크롬 브라우저에서만 테스트 가능하다. 이게 문제네…

google-chrome-1326908_640

Blogger Widget