ギターが優しく泣いている 3 (プログラム編)
変数とテーブルの説明だけで何かわからなくなってきました。時間を置くと本人が簡単に別人に変身してしまうので、開発時に作ったドキュメント(特になにげないメモ)を保存しておくことは本当に重要だと痛感します。それでも、めげずにプログラム本体の説明をします。
//*************************************************************
// 12弦ギターのシミュレート
// MPLAB Ver.5.25
// XC8 Ver2.10
//*************************************************************
uint8_t t_no;
uint8_t g_no;
uint8_t s_no;
uint8_t arpe_no;
uint16_t tab; //1bit:6(12)弦・・・12bit:1弦
uint16_t pattern[6];
uint8_t point;
uint8_t dnib;
uint8_t unib;
// CONFIG1
#pragma config IESO = ON
#pragma config BOREN = ON
#pragma config PWRTE = OFF
#pragma config FOSC = INTOSC
#pragma config FCMEN = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config WDTE = OFF
#pragma config CLKOUTEN = ON
// CONFIG2
#pragma config WRT = OFF
#pragma config LVP = OFF
#pragma config STVREN = ON
#pragma config PLLEN = OFF
#pragma config BORV = LO
#define _XTAL_FREQ 32000000
#define ON 1
#define OFF 0
#define EF 0xF0 // EndFileを示す識別子
#define NP 0xF1 // NotPlayを示す識別子
#define T0COUT 206 // Timer0 100us:206
#define PRESCALE 4 // 100μs:4
//*************************************************************
//割り込みルーチン
//*************************************************************
void __interrupt () InterTimer( void ){
//結局、タイマ0割り込みは使用しませんでした
if(INTCONbits.TMR0IF == 1){
TMR0 = T0COUT; //100us
if(Task_SW >= 3) Task_SW = 0;
Task_SW++;
INTCONbits.TMR0IF = 0;
}
//タイマ1割り込み
if(PIR1bits.TMR1IF == 1){
TMR1H = 224; //1ms timer
TMR1L = 192;
//T時間のカウントを行なう
for( tcount = 0; tcount < 12; tcount++ ){
// T bits 01:ON
if((ST[tcount] & 0b11111111) == 0b00000100){
timer[tcount]++;
if(timer[tcount] > tmrT[tcount]) {
ST[tcount] &= 0b11110011;
// T bits 10 up
ST[tcount] |= 0b00001000;
timer[tcount] = 0;
}
}
}
//G時間のカウントを行なう
for( gcount = 0; gcount < 12; gcount++ ){
//G bits 01:ON
if((ST[gcount] & 0b11111111) == 0b00011101){
timer[gcount]++;
if(timer[gcount] > tmrG[gcount]) {
ST[gcount] &= 0b11001111;
// 01:up
ST[gcount] |= 0b00100000;
timer[gcount] = 0;
}
}
}
//S時間のカウントを行なう
for(scount = 0; scount < 12; scount++ ){
// S bits 01:ON
if((ST[scount] & 0b11111111) == 0b01111110){
timer[scount]++;
if(timer[scount] > tmrS[scount]) {
ST[scount] &= 0b00111111;
// 01:up
ST[scount] |= 0b10000000;
timer[scount] = 0;
}
}
}
PIR1bits.TMR1IF = 0;
}
}
//*************************************************************
// メインルーチン
//*************************************************************
void main(void){
OSCCONbits.SPLLEN = 1; // PLL X4
OSCCONbits.IRCF = 0b1110; // IRCF 8MHz_HF
OSCCONbits.SCS = 0; // INTOSC
OSCSTATbits.T1OSCR = 0; // disabled
OSCSTATbits.PLLR = 0; // 4XPLL disable
OSCSTATbits.OSTS = 0; // intosc
OSCSTATbits.HFIOFR = 0; // disabled
OSCSTATbits.HFIOFL = 0; // not0.2percent_acc
OSCSTATbits.MFIOFR = 0; // disabled
OSCSTATbits.LFIOFR = 0; // dsiabled
OSCSTATbits.HFIOFS = 0; // not0.5percent_acc
OSCTUNEbits.TUN = 0;// factory-calibrated frequency
// デジタルIOのみ
ANSELA = 0b00000000 ;
// RA1:out 他は適当
TRISA = 0b00111100 ;
PORTA = 0b00000000 ; // all L
// すべてデジタルIO
// MIDI系統のみ規定。他は適当。
ANSELB = 0b00000000 ;
TRISB = 0b00001110 ;
WPUB = 0b00000000 ;
PORTB = 0b00000000 ;
APFCON1bits.TXCKSEL = 1 ; //1:RB5 0:RB2
APFCON0bits.RXDTSEL = 1 ; //1:RB2 0:RB1
//Timer0 init(今回未使用)
prescaler = PRESCALE;
if (prescaler == 0) {
OPTION_REGbits.PSA = 1;
} else {
OPTION_REGbits.PSA = 0;
OPTION_REGbits.PS = prescaler - 1;
}
OPTION_REGbits.TMR0CS = 0; //fosc/4
OPTION_REGbits.TMR0SE = 0;
INTCONbits.TMR0IE = 1;
//INTCONbits.PEIE = 1;
//Timer1 init
T1CONbits.TMR1ON = 1; //有効にする
T1CONbits.TMR1CS = 0; //fosc/4
T1CONbits.T1CKPS = 0; //prescaler 0:2^0
TMR1H = 224; //1ms timer
TMR1L = 192;
PIE1bits.TMR1IE = 1;
INTCONbits.PEIE = 1;
//UART
TXSTAbits.CSRC = 0; // don't care
TXSTAbits.TX9 = 0; // 8 bit
TXSTAbits.TXEN = 1; // enable
TXSTAbits.SYNC = 0; // 非同期モード
TXSTAbits.SENDB = 0; // break
TXSTAbits.BRGH = 0; // Low
TXSTAbits.TRMT = 0; // TSR full
TXSTAbits.TX9D = 0;
//RCSTA
RCSTAbits.SPEN = 1; // serial port enable
RCSTAbits.RX9 = 0; // 8bit
RCSTAbits.SREN = 0; // don't care
RCSTAbits.CREN = 1; // enable
RCSTAbits.ADDEN = 0; // don't care
RCSTAbits.FERR = 0; // disable
RCSTAbits.OERR = 0; // over run error
RCSTAbits.RX9D = 0;
BAUDCON = 0; //BRG16 0
SPBRG = 15; // ボーレートを31250bpsに設定
INTCONbits.GIE = 1;
// 9n : midi channel = 0;
midi_ch = 0b10010000;
//ここから主動作のルーチンです。大まかな処理を説明すると
// ①P[ ][ ] から演奏するギターコード、M[ ]で奏法を選択
// ②Upストロークの場合は発音する順番を入れ替え
// ③発音時間は奏法により異なる。
while(1){
uint8_t i;
uint8_t j;
if( P[0][measure] != EF ){
// Level= 0:OFF 1:Down 2:Up 3-5:Arpe*
Level = M[measure] ;
bass_flg = OFF;
for(i = 0 ; i < 12 ;i++ ){
// Upストロークの時
if(Level == 2){
//発音順番を変更
j = ~i - 0b11110100;
F[i] = code[ P[0][measure] ][j] ;
N[i] = open[j];
} else { //Down,Arpe*の時
F[i] = code[ P[0][measure] ][i] ;
N[i] = open[i];
}
// 発音タイミング生成
if( F[i] != NP ){
string |= ( 1 << (uint16_t) i);
if(bass_flg == OFF){
bass_flg = ON;
//root音(bass)の決定
bass = i;
}
}
ST[i] = 0;
}
switch( Level ){
case 1: // DownとUp
case 2:
Stroke();
break;
case 3: // Arpe1
arpe_cnt = 6;
Arpe1();
break;
case 4: // Arpe2
Arpe2();
break;
case 5: // Arpe3
Arpe3();
break;
default:
break;
}
measure++;
} else{
measure = 0;
}
}
}
//*************************************************************
//各演奏パターンのルーチン
//*************************************************************
void Stroke(void){
// ①使用するテーブルはP[ ] [ ] と M[ ]です(Arpeとは異なる)。
// ②ST[ ]のフラグにより、T→G→Sの各12弦分のタイマーを作動。
// ③タイマー値を設定し、割り込みルーチンでカウントする。
// ④時間差をつけて12弦分の発音をおこなう
while( string ){ //すべての弦を演奏した?
for (t_no = 0;t_no < 12 ;t_no++){
if((ST[t_no] & 0b11110011) == 0b00000000){
//OFF?
if((ST[t_no] & 0b11111111) == 0b00000000){
//tmrT_sw = ON
ST[t_no] |= 0b00000100;
tmrT[t_no] = Tbl[t_no];
}
//Tタイマーアップ?
if((ST[t_no] & 0b11111111) == 0b00001000){
if(F[t_no] != NP){
//N[]フレットの音階:12(6)弦目から記入
note = F[t_no] + N[t_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch;// ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = V[t_no]; // 送信する
}
ST[t_no] &= 0b11111100;
//Ttimerが完了
ST[t_no] |= 0b00001100;
//tmrG_sw = ここではOFF;Gset 00→01
ST[t_no] |= 0b00000001;
}
}
}
// G
for (g_no = 0;g_no < 12 ;g_no++){
if((ST[g_no] & 0b11001111 ) == 0b00001101){
//OFF?
if((ST[g_no] & 0b11111111) == 0b00001101){
//tmrG_sw = ON;
ST[g_no] |= 0b00010000;
tmrG[g_no] = Tbl[tmr];
}
//Gタイマーアップ?
if((ST[g_no] & 0b11111111) == 0b00101101){
//g_no番目の弦の鳴動OFF(midiへOFF出力)
//Gtimerが完了
ST[g_no] |= 0b00110000;
if(F[g_no] != NP){
note = F[g_no] + N[g_no];
while(TXIF == 0); // 送信可能?
TXREG = midi_ch;// ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = 0; // string.V[g_no] = 0
}
ST[g_no] &= 0b11111100;
//tmrS_sw = ここではOFF;Sset→10
ST[g_no] |= 0b00000010;
}
}
}
for (s_no = 0;s_no < 12 ;s_no++){ // S
if(( ST[s_no] & 0b00111111 ) == 0b00111110){
//OFF?
if((ST[s_no] & 0b11111111) == 0b00111110){
// tmrS_sw = ON;
ST[s_no] |= 0b01000000;
// 0ms
tmrG[g_no] = Tbl[0];
}
//Sタイマーアップ?
if((ST[s_no] & 0b11111111) == 0b10111110){
//Stimerが完了;Tset→11
ST[s_no] |= 0b11111111;
string &= ~(1 << s_no);
//13-16ビット目をマスク
string &= 0b0000111111111111;
}
}
}
}
}
//*************************************************************
void Arpe1(void){
// ①使用するテーブルはP[ ] [ ]とM[ ](Strokeとは異なる)と、CT[ ]。
// ②ST[ ]のフラグにより、T→G→Sの各12弦分のタイマーを作動。
// ③タイマー値を設定し、割り込みルーチンでカウントする。
// ④CT[ ]で示す時間差で各弦を発音する。
//すべての弦を演奏した?
while( string ){
//00:T 01:G 10:S 11:END
for (t_no = 0;t_no < 12 ;t_no++){ // T
if((ST[t_no] & 0b11110011) == 0b00000000){
//OFF?
if((ST[t_no] & 0b11111111) == 0b00000000){
//tmrT_sw = ON
ST[t_no] |= 0b00000100;
tmrT[t_no] = Tbl[ CT[t_no] ];
}
//Tタイマーアップ?
if((ST[t_no] & 0b11111111) == 0b00001000){
//t_no番目の弦を鳴動(midiへ出力)
if(F[t_no] != NP){
//N[]フレットの音階:12(6)弦目から
note = F[t_no] + N[t_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch;// ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = V[t_no]; // 送信する
}
ST[t_no] &= 0b11111100;
//Ttimerが完了
ST[t_no] |= 0b00001100;
//tmrG_sw = ここではOFF;Gset 00→01
ST[t_no] |= 0b00000001;
}
}
}
}
// G
for (g_no = 0;g_no < 12 ;g_no++){
if((ST[g_no] & 0b11001111 ) == 0b00001101){
//OFF?
if((ST[g_no] & 0b11111111) == 0b00001101){
//tmrG_sw = ON;
ST[g_no] |= 0b00010000;
//G時間は各弦共通
tmrG[g_no] = Tbl[ 14 ];
}
//Gタイマーアップ?
if((ST[g_no] & 0b11111111) == 0b00101101){
//g_no番目の弦の鳴動OFF(midiへOFF出力)
ST[g_no] |= 0b00110000; //Gtimerが完了
if(F[g_no] != NP){
note = F[g_no] + N[g_no];
while(TXIF == 0); // 送信可能?
TXREG = midi_ch; // ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = 0; // string.V[g_no] = 0
}
ST[g_no] &= 0b11111100;
//tmrS_sw = ここではOFF;Sset→10
ST[g_no] |= 0b00000010;
}
}
}
// S
for (s_no = 0;s_no < 12 ;s_no++){
if(( ST[s_no] & 0b00111111 ) == 0b00111110){
//OFF?
if((ST[s_no] & 0b11111111) == 0b00111110){
//tmrS_sw = ON;
ST[s_no] |= 0b01000000;
//S時間は無しに設定
tmrS[s_no] = Tbl[0];
}
//Sタイマーアップ?
if((ST[s_no] & 0b11111111) == 0b10111110){
arpe_cnt--;
if(arpe_cnt == 0){
//if(ST[s_no] == 0b11111111)
string &= ~(1 << s_no);
//13-16ビット目をマスク
string &= 0b0000111111111111;
} else {
//Stimerが完了;Tset→11
ST[s_no] = 0b00000000;
}
}
}
}
}
//*************************************************************
void Arpe2(void){
// ①使用するテーブルはP[ ] [ ](Arpe2の)とTap[ ]。
// ②ST[ ]のフラグにより、T→G→Sの各12弦分のタイマー作動。
// ③タイマー値を設定し、割り込みルーチンでカウントする。
// ④メモリ節約のため、Tap[ ]でG時間とS時間を規定している。
// 発音タイミング生成
for( arpe_no = 0 ; arpe_no < 12 ; arpe_no++ ){
F[arpe_no] = P[arpe_no][measure];
if( F[arpe_no] != NP ){
string |= ( 1 << (uint16_t) arpe_no);
N[arpe_no] = open[arpe_no];
ST[arpe_no] = 0;
dnib = Tap[arpe_no][measure] & 0b00001111;
unib = (Tap[arpe_no][measure] >> 4) & 0b00001111;
tmrG[arpe_no] = Tbl[dnib];
tmrS[arpe_no] = Tbl[unib];
}
}
tab = string;
for (t_no = 0;t_no < 12 ;t_no++){
//演奏するフレットか?
if((tab >> t_no) & 1){
if(F[t_no] != NP){
//N[]フレットの音階:12(6)弦目から記入
note = F[t_no] + N[t_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch; // ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = V[t_no]; // 送信する
}
//Tタイマーは処理済みにする
ST[t_no] = 0b00001101;
}
}
while(string){
for (g_no = 0;g_no < 12 ;g_no++){
arpe_cnt = (uint16_t) g_no;
//演奏するフレットか?
if((tab >> arpe_cnt) & 1){
//G
if((ST[g_no] & 0b11001111) == 0b00001101){
//OFF?
if((ST[g_no] & 0b11111111) == 0b00001101){
//tmrG_sw = ON
ST[g_no] |= 0b00010000;
}
//Gタイマーアップ?
if((ST[g_no] & 0b11111111) == 0b00101101){
ST[g_no] |= 0b00110000;
if(F[g_no] != NP){
//N[]フレットの音階:12(6)弦目から記入
note = F[g_no] + N[g_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch; // ノートオフ送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = 0; // 送信する
}
ST[g_no] &= 0b11111100;
//tmrS_sw = ここではOFF;Sset 01→10
ST[g_no] |= 0b00000010;
}
}
}
}
// S
for (s_no = 0;s_no < 12 ;s_no++){
arpe_cnt = (uint16_t) s_no ;
//演奏するフレットか?
if((tab >> arpe_cnt) & 1){
if(( ST[s_no] & 0b00111111 ) == 0b00111110){
//OFF?
if((ST[s_no] & 0b11111111) == 0b00111110){
//tmrS_sw = ON;
ST[s_no] |= 0b01000000;
}
//Sタイマーアップ?
if((ST[s_no] & 0b11111111) == 0b10111110){
//Stimerが完了;Tset→11
ST[s_no] |= 0b11111111;
string &= ~(1 << s_no);
//13-16ビット目をマスク
string &= 0b0000111111111111;
}
}
}
}
}
}
//*************************************************************
void Arpe3(void){
// ①使用するテーブルはP[ ] [ ]とCT[ ]とpattern[ ]です。
// ②ST[ ]のフラグにより、T→G→Sの各12弦分のタイマーを作動。
// ③タイマー値を設定し、割り込みルーチンでカウントする。
// ④pattern[ ]で1ピッキングあたりの弦を順次に発音する。
uint8_t t_no;
uint8_t g_no;
uint8_t s_no;
uint8_t arpe_no;
uint16_t tab; //1bit目:6(12)弦・・・12bit目:1弦
//アルペジオのroot音の探索と順番カウンタ
for(arpe_no = 0;arpe_no < 6; arpe_no++){
tab = pattern[arpe_no];
//4(7)弦から6(12)弦でroot音は?
if( tab & 0b0000000000111111){
tab &= 0b1111111111000000;
//12弦であること
tab |= (uint16_t) ( 0b000000011 << bass );
}
string = tab;
tmr = CT[arpe_no] ; // TmrG[tmr]
for (t_no = 0;t_no < 12 ;t_no++){
//演奏するフレットか?
if((tab >> t_no) & 1){
if(F[t_no] != NP){
//N[]フレットの音階:12(6)弦目から記入
note = F[t_no] + N[t_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch; // ノートオン送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = V[t_no]; // 送信する
}
//Tタイマーは処理済みとする
ST[t_no] = 0b00001101;
}
}
while(string){
for (g_no = 0;g_no < 12 ;g_no++){
arpe_cnt = (uint16_t) g_no;
//演奏するフレットか?
if((tab >> arpe_cnt) & 1){
//G
if((ST[g_no] & 0b11001111) == 0b00001101){
//OFF?
if((ST[g_no] & 0b11111111) == 0b00001101){
//tmrG_sw = ON
ST[g_no] |= 0b00010000;
tmrG[g_no] = Tbl[tmr]; //
}
//Gタイマーアップ?
if((ST[g_no] & 0b11111111) == 0b00101101){
ST[g_no] |= 0b00110000;
if(F[g_no] != NP){
//N[]フレットの音階:12(6)弦目から記入
note = F[g_no] + N[g_no] + capo;
while(TXIF == 0); // 送信可能?
TXREG = midi_ch; // ノートオフ送信
while(TXIF == 0); // 送信可能?
TXREG = note; // 送信する
while(TXIF == 0); // 送信可能?
TXREG = 0; // 送信する
}
ST[g_no] &= 0b11111100;
//tmrS_sw = ここではOFF;Sset 01→10
ST[g_no] |= 0b00000010;
}
}
}
}
for (s_no = 0;s_no < 12 ;s_no++){ // S
arpe_cnt = (uint16_t) s_no ;
//演奏するフレットか?
if((tab >> arpe_cnt) & 1){
if(( ST[s_no] & 0b00111111 ) == 0b00111110){
//OFF?
if((ST[s_no] & 0b11111111) == 0b00111110){
//tmrS_sw = ON;
ST[s_no] |= 0b01000000;
}
//Sタイマーアップ?
if((ST[s_no] & 0b11111111) == 0b10111110){
//Stimerが完了;Tset→11
ST[s_no] |= 0b11111111;
string &= ~(1 << s_no);
//13-16ビット目をマスク
string &= 0b0000111111111111;
}
}
}
}
}
}
}
//*************************************************************■実は・・・・・
YouTubeの動画を見ていると、アップ/ダウン・ストロークの演奏の後にスライド・バーによる演奏が続いていたのでした。これもイントロに含まれますね。この部分のTAB譜を見ると、奇妙な記号が出てきます。これがスライド・ギター奏法をあらわすらしいです。今回はいろいろ試してみたのですが、同じような効果が実現できませんでした。ギターの音色も変えたほうが良さそうなので、しばらく研究してみることにします。
YouTubeの動画を見ていると、アップ/ダウン・ストロークの演奏の後にスライド・バーによる演奏が続いていたのでした。これもイントロに含まれますね。この部分のTAB譜を見ると、奇妙な記号が出てきます。これがスライド・ギター奏法をあらわすらしいです。今回はいろいろ試してみたのですが、同じような効果が実現できませんでした。ギターの音色も変えたほうが良さそうなので、しばらく研究してみることにします。
キーワードは、スライドバー 、 ボトルネック
余談ですが、スライド・バーをお酒の瓶のくびを切って自作したことがあります。あれはどこに行ったのだろう。でも、最近は専用のスライド・バーが安く買えるみたいです。
■感想
アップ・ダウンストロークの演奏ですが、DX7に接続してみたところ、弦と弦の間の時間差や12弦ギターの感じは少しはでているように思いました。ストロークの時間(G時間)を適切に調整して、S時間は0にしてやると、いい線まではいくかなと思いました。著作権の問題で、コード進行や実際の演奏音は出せませんが、各時間をリアルタイムに調整できればもっと楽しめるでしょう。
そして、アルペジオ演奏(Arpe1〜Arpe3)ですが、どれもこれも一長一短があるようです。おすすめしないのはArpe2グループで、参考のデータを見て「これは・・・」と感じたら多分正解です。普通の楽譜がコスパ最高と思えるでしょう。指使いをリアルに再現できるのはArpe3のほうです。何よりピッキングのタイミングが重要みたいです。プログラムを後から付け足して行く方法で仕上げたので、テーブルのデータがわかりづらくなってしまいました。
最後にもっとおもしろいようにするために以下のように改善を図っていこうと思います。
そして、アルペジオ演奏(Arpe1〜Arpe3)ですが、どれもこれも一長一短があるようです。おすすめしないのはArpe2グループで、参考のデータを見て「これは・・・」と感じたら多分正解です。普通の楽譜がコスパ最高と思えるでしょう。指使いをリアルに再現できるのはArpe3のほうです。何よりピッキングのタイミングが重要みたいです。プログラムを後から付け足して行く方法で仕上げたので、テーブルのデータがわかりづらくなってしまいました。
最後にもっとおもしろいようにするために以下のように改善を図っていこうと思います。
●変化を目で見えるようにする
●時間(T,G,S)・ノート信号・Volumeはロータリーエンコーダー(RE)などで操作して、連続で変化できるようにすること
●コード名やテンポ、ストロークなどはわかりやすく指定できること。
やはりピアノロールのようなグラフィカル画面でタイミングやノートを変化出来るようにしたほうが良い。
●時間(T,G,S)・ノート信号・Volumeはロータリーエンコーダー(RE)などで操作して、連続で変化できるようにすること
●コード名やテンポ、ストロークなどはわかりやすく指定できること。
やはりピアノロールのようなグラフィカル画面でタイミングやノートを変化出来るようにしたほうが良い。
今日の作業はここまで。
食材店で眺めていたらコアントローの54度というのを見つけた。アブサン化したのと思ったら製菓用のらしかった。香りが大好きなコアントロ・サワーで乾杯。
**** 回路図が非公開になっていたので修正しました。*****
※このブログで書かれた内容によって生じた損害等の一切の責任を負いかねますので、予めご了承下さい。
コメント 0