关于自制utau软件,widegt,动态更改控件长度等等经验

首先,源代码在这里下载
utau-qt重写,gitee

是个写着玩的项目。

实现这个项目,我首先得知道以下几个东西,wav,提取wav音调的算法等等。

wav的解释已经很多了,懂得都懂,网上信息很多,只想说,懂得都懂。

struct wav_struct
{
    unsigned long file_size;        //文件大小
    unsigned short channel;            //通道数
    unsigned long frequency;        //采样频率
    unsigned long Bps;                //Byte率
    unsigned short sample_num_bit;    //一个样本的位数
    unsigned int data_size;        //数据大小
    unsigned char* data;            //音频数据 ,这里要定义什么就看样本位数了,我这里只是单纯的复制数据
};

这是读取代码的结构体,看一下就知道怎么回事了
对照着看就知道了。。。这里是16进制,hexedit查看

很多人查找wav的变调算法,最后找到这个
https://www.cnblogs.com/cpuimage/p/8321878.html

 wavBuffer = wavRead_float(in_file, &sampleRate, &totalSampleCount);

这一段这个函数我也没有找到。。。233333wav.h的历史版本也没有。不过这个代码很简单,其实就是把波形文件转换成float数组而已2333,所以有没有这个

另外
#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
DR_WAVE_FORMAT_IEEE_FLOAT这玩意在dr_wav.h里面就是一个define的玩意,所以这个头文件我们是可以摆脱滴

 for (unsigned long k =0; k<(int)WAV2.data_size*sounds[i].split; k = k + 2)
    {       
        //右边为大端
        unsigned long data_low = WAV2.data[k];
        unsigned long data_high = WAV2.data[k + 1];
        double data_true = data_high * 256 + data_low;
        long data_complement = 0;       
        //取大端的最高位(符号位)
        int my_sign = (int)(data_high / 128);
        //printf("%d ", my_sign);
        if (my_sign == 1)
        {
            data_complement = data_true - 65536;
        }
        else
        {
            data_complement = data_true;
        }
        //printf("%d ", data_complement);
        setprecision(4);
        double float_data = (double)(data_complement/(double)32768);    
        //cout<<k/2<<endl;
        hex2[k/2]=float_data*sounds[i].sound;//响度设置,如你所见
        //cout<<hex2[k/4]<<endl;

这个代码是另一个项目。。。2333,开源中国找到的,但是忘记是谁了。由于double是八个字节,所以里所应当数组是data的一半23333

然后得到的数组就是buffer了!

 smbPitchShift(pitchShift, (WAV2.data_size/2)*sounds[i].split, 2048, 4, WAV2.frequency, hex2, hex2);//我这个split是切片操作,把信息切片,utau嘛。如果你需要用可以删掉

又是一个开源项目,smbPitchShift,有年头了。虽然算法看不懂(建议先学习fft),但是这个函数会用就行了。pitchShift这个是升降调的元素。

现在进入gui的地方。gui选择了我喜欢(会用的)qt。
在这里插入图片描述

设计也蛮简单的,就是套了两层qwiget,里面不绑定,有其他用处。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{


    ui->setupUi(this);
    this->resize(200,200);//重置主窗口
    ui->widget -> installEventFilter(this);//设置发信装置(应该是这个叫法?)
    edit = new QLineEdit;//这个得new,所以我头文件定义了一改QLineEdit
    hasPress = false;//这个是控制不随意生成新控件的函数
    lastPnt = QPoint(0, 0);
    ui->tab->setMinimumSize(200,200);//设置tab最小界面
    QPalette palette = ui->widget->palette();//这玩意设置背景
    //palette.setBrush(QPalette::Window,QBrush(QColor(61,61,61)));
    palette.setBrush(QPalette::Background,QBrush(QPixmap(":/new/prefix1/text.png")));//2333这个图片是一个xlsx里面截取出来的,利用qt背景图片平铺的鬼畜特性
    ui->widget->setAutoFillBackground(true);
    ui->widget->setPalette(palette);
    QScrollArea *m_pScroll = new QScrollArea(ui->tab);
    m_pScroll->setWidget(ui->widget);//给widget_2设置滚动条
    ui->widget->setMinimumSize(4400,4700);//这里注意,要比主窗体的尺寸要大,不然太小的话会留下一片空白
    QHBoxLayout *pLayout = new QHBoxLayout;//这个很重要
    pLayout->addWidget(m_pScroll);
    pLayout->setMargin(0);
    pLayout->setSpacing(0);
    ui->tab->setLayout(pLayout);

    // 初始化button并设置button的大小和位置。
}

bool MainWindow::eventFilter(QObject * b, QEvent *evt)
{
    QMouseEvent* e = static_cast<QMouseEvent*>(evt);
    if(b==edit)
    {
        //qDebug()<<"yes we did";
        if (evt->type()==QEvent::FocusOut)    // 这里指 lineEdit1 控件的失去焦点事件
                  {
            clearFocus();
            edit->close();

                   }
    }else if(b==ui->widget)
    {
        if(evt->type()==QEvent::MouseButtonPress && e->button()==Qt::LeftButton)
        {
            static int i=0;
            //emit clicked();
            qDebug() << i;
            if (hasPress )
            {
                exit;
            }
            if (i>0 && e->x()-10<button3[i-1]->x()+button3[i-1]->width())
            {
                exit;
            }
            if(i==0)
            {
                button3.push_back(new QPushButton("sss",ui->widget));
                change.push_back(new QPushButton("ch",ui->widget));
                //button2=new QPushButton("sss",ui->widget);
                button3[i] -> resize(200, 50);
                change[i]->resize(20,50);
                button3[i] -> setGeometry(e->x(), (e->y()/50)*50,button3[i]->width(), button3[i]->height());
                change[i] -> setGeometry(e->x()+button3[i]->width()-20, (e->y()/50)*50,change[i]->width(), change[i]->height());
                button3[i] -> installEventFilter(this);
                button3[i]->show();
                change[i]->installEventFilter(this);
                change[i]->show();
                i++;
             }
            else {
                if(e->x()>button3[i-1]->x()+button3[i-1]->width())
                {
                    button3.push_back(new QPushButton("sss",ui->widget));
                    change.push_back(new QPushButton("ch",ui->widget));
                    //button2=new QPushButton("sss",ui->widget);
                    button3[i] -> resize(200, 50);
                    change[i]->resize(20,50);
                    button3[i] -> setGeometry(e->x(), (e->y()/50)*50,button3[i]->width(), button3[i]->height());
                    change[i] -> setGeometry(e->x()+button3[i]->width()-20, (e->y()/50)*50,change[i]->width(), change[i]->height());
                    button3[i] -> installEventFilter(this);
                    button3[i]->show();
                    change[i]->installEventFilter(this);
                    change[i]->show();
                    i++;
                }
                else {
                    exit;
                }

            }
        }
    }
   // else if(b==)
    else
    {
    //if (watched ==edit)
    int a=0,c=-1,h=0,n=-1;
    for(int i=0;i<button3.size();i++)
    {
        if(b==button3[i])
        {
            a=1;
            c=i;
        }
        if(b==change[i])
        {
            h=1;
            n=i;
        }
    }

    if(a==1 && evt->type() == QEvent::MouseButtonPress)  // 按下鼠标左键
    {

        if(e->button() == Qt::LeftButton){  //鼠标左键点击
            lastPnt = e -> pos();
            hasPress = true;
         }
        if(e->button()==Qt::RightButton)
        {
           // qDebug()<<"ss";
            //q=1;
            //signalMapper = new QSignalMapper(this);
            q=c;
            hasPress=true;
            edit->setParent(button3[c]);
           // qDebug()<<"ss";
            QString ButtonText = button3[c]->text();
            edit->setText(ButtonText);
            edit->resize(button3[c]->size());
            edit->show();
            edit->setFocus();
            edit->selectAll();
            edit->installEventFilter(this);
           // QPushButton::mouseDoubleClickEvent(event);
        }
    }else if(a==1 && evt->type() == QEvent::MouseMove && hasPress)
    {
       // QMouseEvent* e = static_cast<QMouseEvent*>(evt);
        // 计算新的移动后的位置
        QPoint movePoint = e->pos()-lastPnt + QPoint(button3[c]->geometry().x(), button3[c]->geometry().y());
        // 设置可移动的X和Y的范围
        //bool moveX = movePoint.x() > 0 && movePoint.x() < width() - button -> width();
        //bool moveY = movePoint.y() > 0 &&  movePoint.y() < height() - button -> height();
        bool moveX;
        if(c==0)
        {
            moveX = movePoint.x() > 0 && movePoint.x()<4400;
            if (button3.size()!=c+1)
            {
                moveX = movePoint.x() > 0 && movePoint.x()<4400 && movePoint.x()<button3[1]->x()-button3[1]->width();
            }
        }
        else {
            moveX = movePoint.x() > button3[c-1]->x()+button3[c-1]->width() && movePoint.x()<4400;
            if (button3.size()!=c+1)
            {
                moveX = movePoint.x() > button3[c-1]->x()+button3[c-1]->width() && movePoint.x()<4400 && movePoint.x()<button3[c+1]->x()-button3[c+1]->width();
            }

        }
        bool moveY = movePoint.y() > 0 && movePoint.y()<4650;
        if(moveX && moveY){ // 在X和Y的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            button3[c] -> move(movePoint);
            change[c] -> setGeometry(button3[c]->x()+button3[c]->width()-20, button3[c]->y(),change[c]->width(), change[c]->height());
        }else if(moveX){   // 在X的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            button3[c] -> move(movePoint.x(), button3[c] -> pos().y());
            change[c] -> setGeometry(button3[c]->x()+button3[c]->width()-20, button3[c]->y(),change[c]->width(), change[c]->height());
        }else if(moveY){    // 在Y的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            button3[c] -> move(button3[c]->pos().x(), movePoint.y());
            change[c] -> setGeometry(button3[c]->x()+button3[c]->width()-20, button3[c]->y(),change[c]->width(), change[c]->height());
        }else{
            // do nothing
        }
    }
    //萌萌答的分割线



    if(h==1 && evt->type() == QEvent::MouseButtonPress)  // 按下鼠标左键
    {

        if(e->button() == Qt::LeftButton){  //鼠标左键点击
            lastPnt = e -> pos();
            hasPress = true;
         }
    }else if(h==1 && evt->type() == QEvent::MouseMove && hasPress)
    {
        qDebug()<<h<<a;
       // QMouseEvent* e = static_cast<QMouseEvent*>(evt);
        // 计算新的移动后的位置
        QPoint movePoint = e->pos()-lastPnt + QPoint(change[n]->geometry().x(), change[n]->geometry().y());
        qDebug()<<h<<a;
        // 设置可移动的X和Y的范围
        //bool moveX = movePoint.x() > 0 && movePoint.x() < width() - button -> width();
        //bool moveY = movePoint.y() > 0 &&  movePoint.y() < height() - button -> height();
        bool moveX;
        if(n==0)
        {
            moveX = movePoint.x() > button3[n]->x()+10 && movePoint.x()<4400;
            if (change.size()!=n+1)
            {
                moveX = movePoint.x() > button3[n]->x()+10 && movePoint.x()<4400 && movePoint.x()<change[1]->x()-button3[1]->width();
            }
        }
        else {
            moveX = movePoint.x() > button3[n]->x()+10 && movePoint.x()<4400;
            if (change.size()!=n+1)
            {
                moveX = movePoint.x() > button3[n]->x()+10 && movePoint.x()<4400 && movePoint.x()<change[n+1]->x()-button3[n+1]->width();
            }

        }
        bool moveY = movePoint.y() ==change[n]->y();
        if(moveX && moveY){ // 在X和Y的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            change[n] -> move(movePoint);
            int l=change[n]->x()-button3[n]->x();
            button3[n]->resize(l+10,50);
        }else if(moveX){   // 在X的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            change[n] -> move(movePoint.x(), change[n] -> pos().y());
            int l=change[n]->x()-button3[n]->x();
            button3[n]->resize(l+10,50);
        }else if(moveY){    // 在Y的允许范围内
            //int x=(movePoint.rx()/121)*121;
            int y=(movePoint.ry()/50)*50;
            //movePoint.setX(x);
            movePoint.setY(y);
            change[n] -> move(change[n]->pos().x(), movePoint.y());
            int l=change[n]->x()-button3[n]->x();
            button3[n]->resize(l+10,50);
        }else{
            // do nothing
        }
    }

    return false;
    }
}

事件过滤器全部,有些长。。。我也不太想解释。这个事件过滤器里面有点击widget生成button的事件,我控制了button出现和移动的位置。关于像utau一样调节边缘调整长度的我使用了另一个button数组,在button3每一个产生的地方的末尾生成button,然后根据两个属于不同button数组的button resize button3控件

void MainWindow::on_pushButton_clicked()
{
    qDebug()<<"start"<<endl;
    int o=0;
    int x = button3.size();
    qDebug()<<"x="<<x<<endl;
    infomation test[100];
    for (int i=0;i<x;i++)
    {
        if(i==0 && button3[0]->x()>20)
        {
            int j = button3[0]->x();
            int e = j/200;
            float r = (float)(j-e*200)/200;
            cout<<r<<endl;
            cout<<"ss"<<endl;
            for(int h=1;h<=e;h++)
            {
                test[o].name="empty.wav";test[o].sound=2;test[o].tone=0;test[o].split=1;
                o++;
            }
            test[o].name="empty.wav";test[o].sound=2;test[o].tone=0;test[o].split=r;
            o++;
        }
        else if(i!=0 && button3[i]->x()-button3[i-1]->x()-button3[i-1]->width()>20)
        {
            int j = button3[i]->x()-button3[i-1]->x()-button3[i-1]->width();
            int e = j/200;
            float r = (float)(j-e*200)/200;
            cout<<r<<endl;
            cout<<"ss"<<endl;
            for(int h=1;h<=e;h++)
            {
                test[o].name="empty.wav";test[o].sound=2;test[o].tone=0;test[o].split=1;
                o++;
            }
            test[o].name="empty.wav";test[o].sound=2;test[o].tone=0;test[o].split=r;
            o++;
        }
        string shift = MainWindow::turnstring(button3[i]->text());
        string u=shift+".wav";
        char p[10];
        strcpy(p,u.c_str());
        qDebug()<<p<<endl;
        qDebug()<<"here: "<<button3[i]->text()<<endl;
        wav_struct text =get_wav(p);
        float f = ((float)button3[i]->width())/((((float)text.data_size)/449104)*200);
        qDebug()<<p;
        int t=button3[i]->width();
        if(f>1)
        {
            f=1;
            t=((((float)text.data_size)/449104)*200);
            qDebug()<<"ssss"<<t;

        }
        qDebug()<<"test"<<p<<endl;
    cout<<"but"<<endl;
     test[o].name=p;test[o].sound=2;test[o].tone=button3[i]->y()/50-10;test[o].split=f;
     //qDebug()<<"finally"<<i<<test[i].name;
     o++;
     cout<<"o:"<<o<<endl<<endl;
    }
    cout<<1<<endl;
    //cout<<test[0].name<<test[1].name<<test[2].name<<"yes";
    make(test,o);
}

这一段是合成的部分。由于手动生成不知道出了啥毛病。。。。我选择用一个空音频文件合成。。。就这样了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值