태그 보관물: 프로그래밍

[RPI-PICO] 오디오 쥬크박스 만들기 2

이전글들

우선 하드웨어 구성은 아래와 같습니다.

Waveshare Pico-Audio original revision
Waveshare Pico-LCD-1.44
Raspberry Pi Pico
microSD Card Adapter
Waveshare Expander Quad

이중에서 Pico-Audio는 I2C 연결
Pico-LCD-1.44는 SPI 연결
microSD Card Adapter도 SPI 연결이구요

라즈베리파이 피코가 SPI 채널이 두개라, 잘 안겹치게 배정해서 소스코드에 기재하면 됩니다. Expander를 쓰기 때문에 하드웨어적으로는 일단 조정을 잘 안해도 되고 다만 microSD Card Adapter의 경우 핀 구조상으로 Expander에 못끼우기에 점퍼케이블을 female to female로 연결해야 하네요.

본래 Expander Dual을 썼는데 모듈을 하나 더 달아야 해서 Quad로 바꾼 것도 특기해야 합니다.

일단 기존의 샘플 코드를 분석해서 흐름을 꿰찰려고 했는데요. Pico-LCD-1.44의 네개 버튼 시연 코드를 일부 떼어내어 가져와서 메뉴를 구성하고 키값을 구해서 눌린지 확인하는 조건문 코드 안에 Pico-Audio 시연 코드에 들어있는 톤 재생 코드를 두니 버튼 누르면 재생이 되었습니다.

그러나 같은 키를 한번 더 누르면 멈추게 하는 것을 살펴봐야 했고, 이는 제작사에서 제시한 라이브러리로 가능한데요. 음질의 경우 톤으로 내는 것은 소스코드에 텍스트 정보로 톤 정보로만 저장되어 재생되는 구조라 음질이 조금 좋은 부저 정도라, MP3 정도는 되어야 하기에 그만두고 microSD Card Adapter를 구해서 연결해보았습니다. microSD 카드에 MP3를 저장해서 불러오는 용도였죠.

microSD 카드는 킹스턴 제품으로, SDHC class 10 UHS-I 지원 제품인데요. 어떤 이유로 인해 FatFS를 사용하는 모든 기존의 프로젝트에서 f_mount() 실행시 error: physical drivce does not work 같은 오류가 나면서 마운트에 실패합니다.

몇가지 이상 증상은

  • LED 점멸로 상태작동을 보여주는 기능이 작동하다가 안하다가 하는데 무조건 마운트 실패
  • BOOTSEL 연결시 PC에 30초 가량 딜레이가 발생하면서 마우스 커서 버벅임
  • 라즈베리파이 피코 내장 플래시가 2MB인데, 무려 127MB로 60배가 뻥튀기되어 보임
  • 아무런 파일도 기록이 안되던 microSD 카드에 이상한 파일과 디렉토리가 발견

인데요.

뭔가 이상해서 macOS에서도 해보니 똑같이 f_mount()에서 안돕니다.

아무래도 FatFS에서 내부적으로 쓰는 코드 중에 SPI 핀과 SD 카드 명세는 잘 해놨어도 ff.c 같은 파일에서 지정하는 매크로 상수를 튜닝해야 제가 쓰는 microSD 카드와 호환된다는 것 같았는데 위 증상을 보면 석연치 않지만, 일단은 프로젝트 저자들도 SD 카드 브랜드가 문제라고 하기도 하네요. 잘 생각해보면 브랜드마다 사양도 다르고, 특히 블락 크기 설정 같은 설정도 잘 살펴서 해야 할 것 같습니다.

그래서 우선 재껴두고 집에 있는 USB 메모리를 달아 해보려고 하는데요. 라즈베리파이 피코의 USB 단자에 USB 메모리를 장착하고, Expander Quad에 별도로 있는 USB 단자로 전원공급을 해서 해볼 생각입니다. 라즈베리파이 피코를 MSC 호스트로 두고 해보는 것이죠. TinyUSB로 비슷한 작업을 하는게 되던데 잘 살펴보고 있습니다.

일단 USB 표준부터 보고 있고 단행본 입수전에 연구논문과 학위논문을 찾아서 일반적인 해설을 한 부분을 집중해서 보려고 하네요.

FatFS가 작동하면 128kbps 44.1kHz MP3 파일을 네개 저장해서 불러와서 LCD의 키로 메뉴 선택후 I2S로 재생하는 것을 할 것입니다.

FatFS로는 일단 집에 있는 USB 메모리로 해보고, 시간이 가면 microSD 카드를 최대한 작은 용량으로 오래전 사양으로 맞추어보려고 합니다. 둘다 안되면 FatFS 소스코드를 뒤적여서 하드웨어 명세를 맞추어줘야죠.

오디오 재생은 제가 쓰는 Pico-Audio original revision이 PCM5101A를 디코더로 쓰는데요. 32비트 384kHz까지 감지한다고 되어 있고 다이나믹 레인지가 106dB입니다. 44.1kHz 128kbps MP3 재생에 지장이 없습니다. 라즈베리파이 피코 C SDK에 포함된 USB 사운드 카드 모드로 돌려보면 음질이 좋습니다.

일단 USB MSC부터 살펴보면서 공부한 것을 정리해서 올리겠습니다.

[RPI-PICO] 라즈베리파이 피코의 USB 단자를 통한 Virtual COM Port 시리얼 모니터 사용법

vscode에 Raspberry Pi Pico 확장기능이 잘 설치되어 있다는 가정 하에 진행합니다. (특히 Serial Monitor)

우선 CMakeLists.txt에 아래 코드를 추가합니다

이 코드는 USB에 stdio를 허용하고 UART에는 비허용하는 코드입니다.

그리고 C 코드의 main() 함수에 아래 코드를 추가합니다.

이렇게 해두고 컴파일해서 uf2를 라즈베리파이 피코에 심습니다.

vscode에서 시리얼 모니터를 열고 Toggle Sent Message Echoing 버튼을 누르고 Start Monitoring 버튼을 누릅니다. 그러면 라즈베리파이 피코가 USB에 연결된 상태라면 BOOTSEL이든 일반 연결 모드든 위에 printf()문으로 보낸 정보가 시리얼 모니터에 뜹니다.

처음 연결했다면 printf() 문이 이미 실행되고나서 시리얼 모니터가 켜졌을때 표시가 안될 수 있으니, Toggle Sent Message Echoing을 켜고 Start Monitoring 상태에서 USB를 뺏다 꽂으면 됩니다.

이를 잘 활용하면 함수 실행 결과를 받아와서 조건문으로 검사하고 오류가 난 것을 보여줄 수 있습니다.

[RPI-PICO] 오디오 쥬크박스 만들기 1

라즈베리파이 피코로 쥬크박스를 만들어보려고 합니다. 하드웨어 구성은 살펴볼 필요가 없이 아래처럼 조합했습니다.

라즈베리파이 피코 (RP2040)
Waveshare Pico-LCD-1.44
Waveshare Pico-Audio
Waveshare Dual GPIO Expander

이구요.

https://www.waveshare.com/wiki/Pico-LCD-1.44
https://www.waveshare.com/wiki/Pico-Audio

에서 사양과 해설이 나옵니다. 라이브러리도 제공되네요.

LCD 모듈은 SPI 연결이고 TFT-LCD라고 되어있구요. 스위치가 제공되어 메뉴에서 항목 선택시 해당 기능을 실행하게 하는게 가능합니다. 쥬크박스 메뉴 표시와 선택기로 쓸 것이구요. 라이브러리가 잘 되어 있어서 LCD 구동후 표시한 메뉴에서 스위치문으로 신호를 받아 메뉴가 구현됩니다.

오디오 모듈은 I2C 연결이구요. PCM5101A 디코더가 탑재되어 있습니다. 32비트 384kHz의 사양에 다이나믹 레인지가 106dB이네요. 오디오 모듈 상품에 스피커가 포함되어 있습니다.

둘다 전원은 따로 연결하지 않고 라즈베리파이 피코와 연결된 핀으로 받는 것 같은데 자세한 것은 생략합니다.

우선 PCM 원리를 해설하고 들어가겠습니다.

우리 주변의 소리는 아날로그입니다. 음악소리가 스피커에서 나온다든지, 천둥 소리가 들린다는 것은 아날로그 형태의 음압이 발생해서 사람의 귀로 들어가 뇌가 인식하는 것입니다.

음압을 매질이 진동한다고 보면 파형이 되어 그래프처럼 표현하는게 됩니다.

아날로그 소리는 그래프가 매끄럽게 연결된 상태로 그려지구요. 이를 디지털 기기에서 처리할때는 샘플링이라고 해서 표본값을 얻어내서 좌표에 점찍고 처리가 되는 것으로 유비가 됩니다.

우리가 수학시간에 배웠던 것처럼 그래프를 그릴때 함수값에 따라 얻어진 변화값을 구해서 그래프 용지에 찍고나서 이들을 연결하라고 하죠? 이 연결 전의 점을 얻어내는 변화값 추출이 샘플링이고, 이를 이어주는 것이 고음질로 되는 비법입니다.

진폭을 Y축으로 시간을 X축으로 두고 파형을 그렸을때 1초의 소리 신호를 Y축에 따라 높낮이가 그려지는데요. 이때의 소리 신호를 1초에 몇개의 샘플로 얻어내는지에 의해 그래프가 더 매끄럽게 되듯이 샘플링 레이트가 중요한 사양이 됩니다.

즉 1초에 44100개의 샘플이 가능하면 샘플링 레이트는 44.1kHz가 되고 48000개로 가능하면 48kHz가 되죠. 이는 디지털화되었을때 아날로그값이 손실되는 정도를 줄여주고, 음질도 향상시켜줍니다. 그래서 오디오 CD와 DVD-Audio를 구분하기도 하네요.

이와 함께 몇비트라고 할때는 양자화 단계를 의미합니다. 8비트 양자화가 되면 2의 8승인 256 단계가 가능해지구요. 16비트는 2의 16승, 32비트는 2의 32승이 됩니다. 비트는 두가지 값만 가능하니 전체 가능한 단계가 비트로 표현되면 2의 멱수가 됩니다. 이역시도 비트수가 높아지면 정밀한 파형이 되어 음질이 좋아지게 되죠.

이를 펄스로 다룬다고 해서 pulse구요.

샘플이 취해지고 양자화가 이루어지면 각 샘플에는 이진수가 주어집니다. 16비트라면 0000 0000 0000 0000에서 1111 1111 1111 1111가 가능해지는데 이게 코드(code)입니다.

즉 PCM(pulse code modulation)은 소리를 펄스화해서 코드로 바꾸는 변조라는 의미입니다.

이는 ADC(Analog to Digital Converter)로 자연상태의 소리를 디지털화하게 되구요. DAC(Digital to Analog Converter)를 쓰면 음악파일을 스피커로 출력하는 모듈에 채택이 됩니다. 둘다 가진 모듈이 있고 하나만 가진 모듈도 있는 것 같습니다.

사양적으로 32비트, 384kHz를 제공하는 경우에는 이 전체 사양을 다 만족하는 오디오 데이터라고 해도 늘 이 전체를 다 쓰는건 아니구요. 다이나믹 레인지와 필터링, 인터폴레이션, 밴드 리미트 등의 처리를 해야 되는 알고리즘의 특성상, 사양 그대로보다는 입력 데이터와 처리 알고리즘의 특성에 의해 다 쓰이는 것은 아니죠.

다이나믹 레인지는 보통 6dB 마다 1비트씩 는다고 보면 된다는데, 106dB인 경우 대충 17.6 비트네요.

필터링, 인터폴레이션, 밴드 리미트와 같은 기술은 파형으로 다루는 소리 데이터에 노이즈를 적게 하는 용도로도 쓰이고, 파형 자체를 증폭하거나 커트해야 할 필요에 의해 제정된 기술인데 이게 제작사의 기술력과 관련이 있네요.

PCM5101A 데이터시트에 나온 사양도 이로부터 이해가 됩니다.

일단 이론 공부는 대충 이렇게 해두구요. 조만간 코딩도 해서 올려보겠습니다.

제작사에 문의해보니 제가 구한 제품이 rev2.1이라던데 다시 확인해보니 오리지날 리비전으로 밝혀졌습니다.

rev2.1은 시러스로직의 CS4344를 디코더로 쓰고 오리지날 리비전은 텍사스 인스트루먼트의 PCM5101A를 쓰는데요. 이둘이 거의 같아보여도 후자가 사양이 좋습니다. CS4344는 32비트 192kHz까지 감지가 되는 기종이고 PCM5101A는 32비트 384kHz까지 감지가 되는데요. 다이나믹 레인지가 106dB이니 출력되는 음질은 비슷할 수도 있습니다. 물론 여러 변인이 존재하니까요.

리비전 문제로 인해 며칠 확인작업을 했는데, 전에 쓴 글에 문의를 다시 보낸다고 언급했으나 새로 쓴 글에서 언급을 안해두어 인상이 나빠질 듯하여 추가해둡니다.

워드프레스에서 문자열에 어귀마다 하이픈을 추가하기

위 워드프레스 API 함수를 쓰면 문자열에서 어귀마다 하이픈을 추가해서 리턴해줍니다.

처럼 실행하면

임의의-문자열을-인자로-넘겨주세요

로 변환된 문자열을 화면에 표시합니다.

위의 예제에서는 echo 함수에 sanitize_title_with_dashes() 함수의 리턴값을 넘겼는데요. echo 함수로 표시하는 기능 외에도 다른 용도로도 응용하면 다른 기능을 구현하는 용도로도 쓸 수 있습니다. 예를 들면 글 제목을 슬러그 형태로 변환하는 기능이 그 예입니다. 워드프레스 슬러그는 문자열을 어귀로 분리해서 하이픈이 사이사이에 들어가야 하므로 위의 함수로 문자열을 조정하면 슬러그 변환이 되게 됩니다.

여기에 더해서 PHP 함수로 rawurlencode() 와 rawurldecode() 를 적절히 써서 위에서 얻어진 문자열을 처리하면 URL 인코딩/디코딩 된 문자열이 얻어집니다. 플러그인 제작을 할때 필요할 수 있네요.

https://www.php.net/manual/en/function.rawurlencode.php
https://www.php.net/manual/en/function.rawurldecode

위와 같이 하면 $encoded 에는 %EC%9E%84%EC%9D%98%EC%9D%98-%EB%AC%B8%EC%9E%90%EC%97%B4%EC%9D%84-%EC%9D%B8%EC%9E%90%EB%A1%9C-%EB%84%98%EA%B2%A8%EC%A3%BC%EC%84%B8%EC%9A%94 가 들어가게 되구요.
$decoded에는 임의의-문자열을-인자로-넘겨주세요 와 같은 디코딩된 문자열이 들어갑니다.

결론:
https://developer.wordpress.org/reference/functions/sanitize_title_with_dashes/
https://www.php.net/manual/en/function.rawurlencode.php
https://www.php.net/manual/en/function.rawurldecode

이들 함수를 잘 활용하면 슬러그 처리시 유익하게 쓸 수 있습니다.

아스트라 프로에서 카테고리별로 다른 디자인 보여주는 방법 아이디어

요즘 만들고 있는 사이트에서 블로그 카테고리별로 글보여주는 레이아웃을 카테고리마다 각각 바꾸어봐야 하는데 보류하고 있습니다.

궁리닷컴 이전 버전 사이트처럼 하나의 인문학서 감성으로 디자인을 해서 레이아웃을 보여주고 싶은데요. 지금은 블로그 테마에 내장된 카테고리 표시 기능으로 글을 보여주느라, 카테고리마다 다른 디자인으로 보여주려면 archive.php와 같은 파일을 직접 고쳐야 합니다.

이게 코딩을 요하는 작업이라 타이핑도 그렇고 이미지 연결도 귀찮으니 다른 방법을 써야 합니다.

아스트라 프로를 스펙트라 무료 버전과 함께 쓰는데요. 다음과 같은 방법으로 카테고리마다 다른 디자인으로 보여주는 방안을 실천해봐야 합니다. 이는 archive.php를 고치는 방법과 다르게 페이지를 생성해서 각각 다른 카테고리를 연결하게 만들어 보여주는 방법입니다.

우선 아스트라 프로가 프로 라이선스로 활성화된 상태에서 스펙트라를 설치하고 페이지 메뉴에서 페이지를 생성하면 됩니다.

(1) 페이지를 각각 만들어 각각 다른 카테고리 표시하도록 설정 (위젯 이용)
(2) 네비게이션 메뉴에 페이지 URL을 링크

이렇게 해두면 카테고리마다 다른 페이지 디자인으로 보여주는게 WYSIWYG 방식으로 지정이 됩니다. (1) 페이지 제작을 할때 페이지 디자인을 달리 해서 저장하면 되죠. 각각의 페이지마다 각각 다른 카테고리를 연결하구요.

여기에

(3) 글 목록 표시시 오프셋 설정이 가능하다면 컬럼으로 나누어 글 제목표시가 가능

인데 (3) 오프셋 설정은 지원되는지 살펴봐야하네요.

이해 잘 되게 해설한지는 모르지만 핵심은 archive.php에 의존하기보다 페이지를 써서 페이지를 각각 만들고 위젯으로 개별 카테고리 글 목록을 표시되게 하면 카테고리마다 다른 디자인으로 보여주는게 된다는 것이네요.

아이디어로 올려봅니다.

(2)를 할때는

<a href=”https://examples.com/category/카테고리명”>카테고리명</a>

보다

<a href=”https://examples.com/페이지명”>페이지명</a>

으로 링크를 하드코딩하거나 디자인 메뉴의 하위 메뉴에서 메뉴 설정을 해서 링크가 걸리게 하면 됩니다.

Flex Posts 플러그인 사용시 발췌문 길이 조정도 안되고 아주 길게 표시될때 해결법

Flex Posts 플러그인은 사이드바에 위젯으로 등록해서 랜덤 포스트, 최신글 표시 등을 담당하는 플러그인입니다.

모종의 이유로 발췌문 표시 조절이 안되고 아주 길게 표시될때 해결법은요.

여러 연쇄적인 실행이 있을테니 이 글에서 말한 것과 다른 원인일 수 있으나, 일단 아래와 같은 플러그인 파일을 들여다보세요.

Flex Posts 디렉토리 아래 template-tags.php

이 파일에서 flex_posts_excerpt() 함수가 직접적으로 발췌문을 표시하는 코드입니다.

제 경우 이 파일과 이 파일 위에 기재된 함수를 고쳐서 해결했는데요.

를 추가하고

flex_posts_excerpt() 함수를 아래와 같이 대체했습니다.

이렇게 해두니 다시 잘 작동합니다.

get_the_excerpt()와 wp_trim_words()로 발췌문 길이 조정하기

발췌문은 플러그인과 같은 추가된 프로그램에서 조정하기도 하지만, 워드프레스 코어에서 제공하는 함수로 조정할 수도 있습니다.

우선 get_the_excerpt()로 발췌문을 가져오는게 가능하구요. 가져온 발췌문을 wp_trim_words()로 잘라내서 잘라진 발췌문을 표시하도록 코딩하면 됩니다.

아래와 같은 코드가 참고가 될 것입니다.

이 경우는

get_the_excerpt() 함수로 현재 처리되고 있는 글의 발췌문을 가져와서
wp_trim_words() 함수로 잘라내고 이를 echo()로 표시하는 코드입니다.

get_the_excerpt()의 잘라내는 기본값은 55글자구요. 위 코드를 쓰면 이를 15로 조정해서 처리할 수 있게 됩니다.

이를 응용해서

처럼 테마 functions.php 파일에 기재해두면 워드프레스 코어의 포스트 임베드 위젯을 쓸때 표시되는 발췌문의 길이를 55로 제한해서 표시하는게 됩니다.

플러그인 위젯으로 발췌문을 표시하는 기능을 쓸때도 이 함수들을 잘 쓰면 좋습니다. 플러그인에서 자체적으로 구현하지 않았다면요. 자체적으로 구현한 코드가 버전이 오래된 등의 이유로 잘 작동하지 않을때도 위의 두 함수를 잘 활용하면 대체가 됩니다. 모종의 이유로 변조된 경우에도 해당됩니다.

웹브라우저 관련 유저 에이전트를 PHP를 써서 확인하고 기능 실행하기

wpcode 관련해서 PHP 코드를 포함시켜도 되는 조건에서 오류가 나기도 하는데요. 이 경우 wpcode 실행시 문제지만 코드 상에서 문제를 찾아야 할때 참고가 되시는 함수가 있네요.

$_SERVER 변수는 기정의 변수로 서버 환경에서 감지된 정보가 저장되어 있는 변수인데요. 저도 $_SERVER[‘HTTP_USER_AGENT’]와 같은 키로 테스트해봤는데 이 키로는 원하는 정보가 안나옵니다.

PHP에서 get_browser() 함수를 쓰는 방안이 있는데요. browscap.ini를 잘 설정하고 쓰면 웹브라우저 유저 에이전트를 알아낼때 필요한 정보가 배열 변수로 반환되어 쓰면 되네요.

https://www.php.net/manual/en/function.get-browser

를 참조하시길요. 함수에 넘기는 인자와 반환된 변수의 값도 나오고 browscap.ini를 설정하는 방법이 나온 링크도 나옵니다.

함수 리턴값으로 아래처럼 되었다면

browscap.ini 를 잘 설정하고 php.ini 에 경로를 기입후 웹서버를 재기동하고,

이런식으로 해두면 작동할 것 같습니다. 배열 변수 키는 위 링크에 나오니 참고하시길요.

아스트라 프로 4.7.0에서 검색결과 500 오류 해결

아스트라 프로 4.7.0으로 클라우드웨이즈에서 어플리케이션 추가를 했습니다. 검색결과를 테스트해보니 500 오류가 나서 아래와 같이 조치했습니다.

(1) wp-config.php 에 define(‘WP_DEBUG’, true); 추가후 관찰
(2) Fatal error: Uncaught ArgumentCountError: 3 arguments are required, 2 given in /var/www/html/wp-content/themes/astra/inc/core/common-functions.php:966 오류 발생
(3) 해당 파일을 테마 편집기로 열어서 보니 $title 변수에 add_filter()가 걸려있고 인자가 두개 관찰
(4) 그래도 작동해야 하지만, 세번째, 네번째 인자를 줘도 같은 오류라 다 966라인을 다 지우고
(5) 그다음 라인 어딘가의 echo $title; 구문을 지우고 $title = “검색 결과: <span>” . the_search_query() . “</span>”; 추가후 재실험
(6) 잘 작동함.
(7) wp-config.php에 define(‘WP_DEBUG’, false); 로 되돌림.

어떤 이유인지는 불명확하지만 이전 버전으로 돌아가는 다른 어플리케이션에서는 잘 되는 검색 기능이 최신 버전으로 새로 만든 어플리케이션에서 안되서 워드프래스 재설치, 플러그인 재설치, 테마 재설치를 해도 안되었습니다. 위와 같이 조치하니 되었네요.

위에 add_filter()는 아스트라 설정에서 제목을 읽어와서 표시할때 필요한 기능인데, 이 기능을 안쓰고 그냥 $title 변수를 하드코딩해서 해결했습니다.

일단 같은 문제가 있다면 참고해보세요. 아스트라 프로에서 구성한 사이트에서 검색기능 실행시 500 오류가 나면 해볼만한 사례입니다.

슬러그 보정 플러그인에 긴급추가할 기능

이제 셀 정렬 기능과 업데이트 확인 기능만 추가하면 끝날 것 같았는데요.

회원분께서 보고해주신 현상 중에 슬러그가 달라져서 영구주소가 변경되면 301 리디렉션을 반드시 해야 되는 것이 유의되네요.

제 플러그인의 기본 제작 방침은 슬러그 변조시 복호화 가능, 불가능 여부에 따라 400 오류나 404 오류가 나는 것을 보정하기 위함인데요. 이게 그냥 고치게 하면 SEO에 문제가 옵니다. 301 리디렉션을 반드시 구현하거나, 조치를 해서 400 오류나 404 오류난 경우를 감지해서 고치게 해야 하네요.

플러그인에 공지를 해서 400 오류나 404 오류가 아니면 하지 말라고 하는 방안도 있구요.
REST API 등으로 가능하면 헤더를 조사해서 400나 404가 반환되어야 슬러그 보정기능을 하게 한다든지요.

이 두가지 경우가 다 가능한 선택지인데 이 경우들에서도 구글에 색인된 정보를 알아내서 301 리디렉션을 자동으로 추가하는 기능이 필요해보이네요.

각각의 기능이 중첩되는 양태에 의해서는 사용상에 혼동이 있을 수 있어서 SEO가 안좋게 되면 큰일입니다.

그래서 출시를 밀어두고 있구요. 제 블로그에서 쓸 용도로만 해보려고 하기도 합니다.

출시할 플러그인은 이번 개발 끝내고 착수할 파워토이즈 개념의 플러그인으로 할까도 생각중이네요 ㅎㅎ SEO와 상관없는 기능을 구현할 플러그인이라 출시가 가능합니다.

여튼 슬러그 보정 기능 실행시 조건화해두어야 할 사안입니다. 301 리디렉션을 해야 한다는 것.