标签归档编程语言

澳门新葡亰官网H2Engine游戏服务器设计的性质管理器

娱乐服务器设计之性管理器

  游戏受角色有所的属性值很多,运营多年之玩乐,往往会来许多个成才线,每个属性都来或为N个成长线模块增减数值。举例当角色戴上铁时hp+100沾,卸下武器时HP-100点,这样加减逻辑只出同高居还比好控制,如果某天有个独特作用当被某技能攻击时,角色武器会为击落,这样尽管会并发减数值的操作不止一远在。如果逻辑处理不当,比如击落的当儿没有当的减数值,再次穿戴武器就造成属性值加了少限,也就算是玩家经常说之刷属性。这种bug对娱乐平衡性影响好非常,反响大恶劣,bug又格外不便被测试发现。本文将介绍一栽管理性之笔触,最酷限度的避免此类bug,如果起bug,也克充分好之排查。

设计思路

  刷属性bug的主导原因是有功能的模块数值加了N次,所以各个模块加的习性要于记录,加了了总得不可知再加。设计这样的数据结构。

//!各个属性对应一个总值
//!各个属性对应各个模块的分值
template<typename T>
class PropCommonMgr
{
public:
    typedef T ObjType;
    typedef int64_t (*functorGet)(ObjType);
    typedef void (*functorSet)(ObjType, int64_t);
    struct PropGetterSetter
    {
        PropGetterSetter():fGet(NULL), fSet(NULL){}        
        functorGet fGet;
        functorSet fSet;
        std::map<std::string, int64_t> moduleRecord;
    };
    void regGetterSetter(const std::string& strName, functorGet fGet, functorSet fSet){
        PropGetterSetter info;
        info.fGet = fGet;
        info.fSet = fSet;
        propName2GetterSetter[strName] = info;
    }
  public:
      std::map<std::string, PropGetterSetter>    propName2GetterSetter;
  };
  1. 有关数据结构的get和set,我们吧每个属性命名一个名,这样处理数量的下会死便于(比如道具配增加性能等等),角色属性有过多种植,这里不克挨个定义,所以属性管理器只是映射属性,并无创造属性值。通过regGetterSetter接口,注册get和set的操作映射。为什么非需要提供add和sub接口能,因为add和sub可以通过get和set组合实现。get和set的接口实现如下:

    int64_t get(ObjType obj, const std::string& strName) {

        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet){
            return it->second.fGet(obj);
        }
        return 0;
    }
    bool set(ObjType obj, const std::string& strName, int64_t v) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fSet){
            it->second.fSet(obj, v);
            return true;
        }
        return false;
    }
    
  2. 至于add和sub,前面提到如果避免刷属性,就务须避免重复加属性。所以每个模块再加属性前须检查一下是否该模块已加了性,如果加了得要是先期减后加。因为每次模块加属性都记录在性管理器中,那么减掉的数值肯定是毋庸置疑的。这样好避另外一栽常见bug,如加了100,减的时节计算错误减了80,也会见积少成多招刷属性。add和sub的代码如下:

    int64_t addByModule(ObjType obj, const std::string& strName, const std::string& moduleName, int64_t v) {

        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod != it->second.moduleRecord.end()){
                ret -= itMod->second;
                itMod->second = v;
            }
            else{
                it->second.moduleRecord[moduleName] = v;
            }
            ret += v;
            it->second.fSet(obj, ret);
            return ret;
        }
        return 0;
    }
    int64_t subByModule(ObjType obj, const std::string& strName, const std::string& moduleName) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod == it->second.moduleRecord.end()){
                return ret;
            }
            ret -= itMod->second;
            it->second.moduleRecord.erase(itMod);
            it->second.fSet(obj, ret);
            return ret;
        }
        return 0;
    }
    int64_t getByModule(ObjType obj, const std::string& strName, const std::string& moduleName) {
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            int64_t ret =it->second.fGet(obj);
            std::map<std::string, int64_t>::iterator itMod = it->second.moduleRecord.find(moduleName);
            if (itMod != it->second.moduleRecord.end()){
                return itMod->second;
            }
        }
        return 0;
    }
    std::map<std::string, int64_t> getAllModule(ObjType obj, const std::string& strName) {
        std::map<std::string, int64_t> ret;
        typename std::map<std::string, PropGetterSetter>::iterator it = propName2GetterSetter.find(strName);
        if (it != propName2GetterSetter.end() && it->second.fGet && it->second.fSet){
            ret = it->second.moduleRecord;
        }
        return ret;
    }
    

  如达到代码所示,addByModule和subByModule必须提供模块名,比如通过装备的下加血量:addByModule(‘HP’,
‘Weapon’, 100),而下武器的时候如果subByModule(‘HP’,
‘Weapon’),因为性管理器知道减多少。

总结

  1. 属性提供一个名映射出好多利益,比如装备配属性,buff配属性的,有名字不无关系联会特别好
  2. 供一个get和set接口的照,这样属性管理器就跟求实的对象的属性字段解耦了。即使是并存的功能模块也可合二为一这个特性管理器。
  3. 性之add和sub操作,都在性管理器中留记录,这样就出现问题,通过getByModule
    getAllModule两独接口也足帮查找问题。
  4. 性管理既合并到H2Engine中,github地址:
    https://github.com/fanchy/h2engine

澳门新葡亰官网Centos7 Zookeeper

正文版权归博客园和作者吴双本人并拥有 转载和爬虫请注明原文地址
www.cnblogs.com/tdws

一.状在前面

ZK是一个快捷的分布式协调服务,高可用的分布式管理协调框架。
朋友推荐一本书《从paxos到zookeeper》,对自身扶的确很老。 

二.集群配置与踩坑

java安装与环境变量配置好参考 http://www.cnblogs.com/tdws/p/4096300.html 

1 wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz   下载
2  
3 tar -zxvf zookeeper-3.4.10.tar.gz   解压
4  
5 mv zookeeper-3.4.10 /usr/local  剪切
6  
7 mv zookeeper-3.4.10/ zookeeper 重命名

下修改配置文件命名

1 cd /usr/local/zookeeper/conf
2 mv zoo_sample.cfg zoo.cfg

部署一共没几推行 。指定安排中的 
dataDir

dataDir=/usr/local/zookeeper/data

自行mkdir创建data文件夹。

以配置文件末尾 配置集群
我是只是台机械伪集群 三个节点

1 server.1=your_ip:20881:30881
2 server.2=your_ip:20882:30882
3 server.3=your_ip:20883:30883

于data文件夹着创造文件myid
来开一个标识

nano myid 在文书中填写0
并且保留。需要注意的凡刚咱们的zookeeper文件夹是未利用的,仅作为我们copy新节点的原来。

属下去复制三卖zk

1 cp -r zookeeper/ zookeeper1
2 cp -r zookeeper/ zookeeper2
3 cp -r zookeeper/ zookeeper3

 

澳门新葡亰官网 1

分别修改三玉节点 其datadir
将路径指定到温馨节点之下

独家修改其端口号及myid,是各个zoo.conf
配置的里port 设置分别吗2181 2182 2183

梯次myid内容分别吗1 2 3

下面 去三个zk bin目录下 执行zkServer.sh
start

澳门新葡亰官网 2

 

第一次 出错

Error contacting service. It is probably
not running.

哎 检查好几只钟头ZK配置文件
试了十几栽艺术,
结果之前JAVA_HOME不小心配置错了,我是yum安装的jdk。

 

第二次 出错与缓解

新兴以起一致次等错误 是自stop zk所有节点之后
再次启动自无来 首先 jps命令 然后望进程id和QuorumPeerMain

把Quorumpeermain的进程kill -9杀死

 

第三次
我丢雷楼某! 这个算麻烦了

如果运用阿里云ECS
专有网络+弹性公网IP

诚如不克一直当ECS实例的程序条例绑定和运用弹性公网IP地址。因为这公网IP地址在ECS之外。所以自己起了拥有的端口,根本无就此,最后以0.0.0.0解决问题。

1 server.1=0.0.0.0:20881:30881
2 server.2=0.0.0.0:20882:30882
3 server.3=0.0.0.0:20883:30883

澳门新葡亰官网 3

澳门新葡亰官网 4

三.澳门新葡亰官网采取与小结

学习ZK一段时间,原生API比较难以使用,一般用zkClient(dubbo因让这)和curator框架来操作ZK比较好。 其突出以场景包括以下几触及:

1.数据公布和订阅

   
ZK在dubbo中当注册中心的角色,服务方和调用方都以此登记。举例来证明,我宣布了一个dubbo
service,消费者webapp引用这服务

 <dubbo:service interface="com.s2s.service.ItemService" ref="itemServiceImpl"/>   发布的服务

 <dubbo:reference interface="com.s2s.service.ItemService" id="itemService"/>     引用服务(将使用RPC调用)

  接下去去服务器上查看数据节点,

澳门新葡亰官网 5

足见见根目录上生dubbo节点,dubbo下有com.s2s.service.ItemService,
其节点下以起consumers和providers等。

澳门新葡亰官网 6澳门新葡亰官网 7

劳动提供者启动时向/dubbo/com.s2s.service.ItemService/providers目录下写副URL

劳务消费者启动时订阅/dubbo/com.s2s.service.ItemService/providers目录下之URL。
并且向/dubbo/com.s2s.service.ItemService/consumers目录下写副好之URL 

督查中心启动时订阅/dubbo/com.s2s.service.ItemService/目录下的享有提供者和顾客URL。

之所以dubbo监控中心,查相顾客与劳务提供者

澳门新葡亰官网 8

澳门新葡亰官网 9

2.载荷均衡

3.命名服务

4.分布式通知及和谐

5.集群管制及Master选举

6.分布式锁

    有许多人口因此她举行分布式锁
但是做法比较底层。临时节点是以同一不行对话内中,保证了出现异常时,锁能好释放。比如client1
做分布式操作 那他创办一个临时节点 然后去开片任何数据操作 做扫尾操作后,
再失管临时节点移除。这时c2才能够去操作。如果生10个客户端
要操作同一个数额,但是这个数量,有多单复制的本子
在不同之DB当中(当然值是相同)。

斯时候 分布式锁之意向就是同步操作。客户端1 操作 这长达数,
那就错过zk立即 就create个节点 代表占用了即漫长数,这时候客户端2
并发操作就漫漫数 先去zk上get一下这个节点,get到之话
可以等待一下,等客户端1 释放掉后,去重新create一下下数据。

7.分布式队列

正文主要是安配置,分布式理论的学还是于好,接下去将见面继续享受实践备受之博。

个人档案中DBL_TRUE_MIN的概念和意向

搬自己2016年11月22日叫SegmentFault发表之章。链接:https://segmentfault.com/a/1190000007565915


于念C Prime
Plus的进程遭到遇到了立道复习题,利用寻引擎加上自己的局部琢磨,初步得出了定论,如发荒唐的远在,还向不吝赐教

下列循环中,如果valuedouble类型,会面世什么问题?

for (value = 36; value > 0; value /= 2)
  printf("%3d", value);

想运行结果:如果valuedouble品种,计算过程遭到会招致极端循环(直到超过double色的精度表示范围),又为printf为整型形式打印数字,会于末出现过多独数字0

答案中指明了这种光景的名词:浮点数下溢(underflow)

实则运作结果:

...(很多个0)
0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0-21474836481073741824536870912-1879048192120795955260397977630198
98881509949447549747237748736188743689437184471859223592961179648589824294912147
4567372836864184329216460823041152576288144 72 36 18  9  4  2  1请按任意键继续.
. .

的确出现了好多独0,但是以许多个0的背后又莫名其妙多发生了同等堆放整数。为了分离有后面的丰富数字,修改格式化字符串为" %3d",结果如下:

...(很多个0)
0   0   0   0   0 -2147483648 1073741824 536870912 -1879048192 1207959552 603
979776 301989888 150994944 75497472 37748736 18874368 9437184 4718592 2359296 11
79648 589824 294912 147456 73728 36864 18432 9216 4608 2304 1152 576 288 144  72
36  18   9   4   2   1请按任意键继续. . .

为进一步将明白产生这种气象之来由,继续修改格式化字符串为" %.3le",结果如下:

...
  4.663e-317 2.331e-317 1.166e-317 5.828e-318 2.914e-318 1.457e-318 7.285e-319 3
.643e-319 1.821e-319 9.107e-320 4.553e-320 2.277e-320 1.138e-320 5.692e-321 2.84
6e-321 1.423e-321 7.115e-322 3.557e-322 1.779e-322 8.893e-323 4.447e-323 1.976e-
323 9.881e-324 4.941e-324请按任意键继续. . .

得视,以整型输出的double类型变量实际上一直以减少,应该是double每当内存中叫截断读取为int此后导致了展示也整数的状况。

查看<float.h>头文件,找到两单跟double列精度有关的明示常量:

#define DBL_MIN          2.2250738585072014e-308 // min positive value
#define DBL_TRUE_MIN     4.9406564584124654e-324 // min positive value

得视,导致循环终止的因由是,循环中最终一个数字4.941e-324除开因2过后的结果小于DBL_TRUE_MIN的值

为什么<float.h>面临假如运用DBL_MINDBL_TRUE_MIN些微只具有同等注释的常量?我首先使用寻引擎查及了这样一个带动注释的版本:

#ifndef DBL_TRUE_MIN
/* DBL_TRUE_MIN is a common non-standard extension for the minimum denorm value
 * DBL_MIN is the minimum non-denorm value -- use that if TRUE_MIN is not defined */
#define DBL_TRUE_MIN DBL_MIN
#endif

诠释部分大意为,DBL_TRUE_MIN是针对性最好小非规格化浮点数(Denormal
number
)的通用非标准扩充,而DBL_MIN才是最好小非规格化浮点数的值,并且仅以DBL_TRUE_MIN莫定义时行使。

C11标准 §5.2.4.2.2.13蒙涉嫌了DBL_TRUE_MIN

The values given in the following list shall be replaced by constant
expressions with implementation-defined (positive) values that are
less than or equal to those shown:
— minimum normalized positive floating-point number,
bemin−1
FLT_MIN 1E-37
DBL_MIN 1E-37
LDBL_MIN 1E-37
— minimum positive floating-point number
FLT_TRUE_MIN 1E-37
DBL_TRUE_MIN 1E-37
LDBL_TRUE_MIN 1E-37
(If the presence or absence of subnormal numbers is indeterminable,
then the value is intended to be a positive number no greater than the
minimum normalized positive number for the type.)

据悉上面查到的音信,我得出了以下的定论:

先是,浮点数在处理器中起规格化数和非规格化数片种植表示法。C标准于这边规定了个别栽浮点数的极小在。具体值的轻重是由于实现来定义的(由编译器等来控制),但是不得低于列有的这些价值。并且,如果没有确定非规格化数是否会出现,DBL_TRUE_MIN的价值应该是一个低于等于该类型最小正规格化数DBL_MIN的值,FLT_TRUE_MINLDBL_TRUE_MIN同理。

本来想快点看了马上按照开的,结果遇见一个施不晓的问题即使翻了那个丰富日子……这个实际上并无是一个吓习惯。不过,反正自己要好已经翻了了,可能出成百上千民用知道不科学的地方,但是只要得以帮助到其他人,我作至这边的目的就达了

澳门新葡亰官网Spring boot入门篇

  1. Spring
    Boot是由Pivotal团队供的崭新框架,其设计目的是为此来简化新Spring应用的始搭建与支出进程。该框架下了特定的措施来开展配置,从而使开发人员不再要定义样板化的配置。通过这种方式,Boot致力为以蓬勃发展的敏捷利用开发领域(rapid
       application  development)成为官员。
     可以 Maven | Gradle | Ant |
    Starters构建项目,参考:http://start.spring.io/ 可以选Maven或Gradle生成Demo,Spring
    boot微服务架构重组Docker容器运行。
      软件版本运行要求要参见官网: Spring boot官网  
    本实例软件版本:JDK1.7 + Spring boot 1.3.5 + Spring 4.2.6 

  常用之starter以及用可列举如下:

(1)spring-boot-starter: 这是中心Spring Boot
starter,提供了大部分基础力量,其他starter都依赖让它,因此无必要显式定义其。

(2)spring-boot-starter-actuator:主要提供监控、管理暨审查应用程序的功用。

(3)spring-boot-starter-jdbc:该starter提供针对性JDBC操作的支撑,包括连接数据库、操作数据库,以及管理数据库连接等等。

(4)spring-boot-starter-data-jpa:JPA starter提供利用Java Persistence
API(例如Hibernate等)的依赖库。

(5)spring-boot-starter-data-*:提供对MongoDB、Data-Rest或者Solr的支持。

(6)spring-boot-starter-security:提供有Spring-security的依赖库。

(7)spring-boot-starter-test:这个starter包括了spring-test依赖以及任何测试框架,例如JUnit和Mockito等等。

(8)spring-boot-starter-web:该starter包括web应用程序的依赖库。

2.Maven构建项目pom代码

  1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3     <modelVersion>4.0.0</modelVersion>
  4 
  5     <groupId>ygnet</groupId>
  6     <artifactId>boot</artifactId>
  7     <version>0.0.1-SNAPSHOT</version>
  8     <packaging>jar</packaging>
  9 
 10     <name>Springboot</name>
 11     <url>http://maven.apache.org</url>
 12     
 13     <properties>
 14         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 15         <java.version>1.7</java.version>
 16     </properties>
 17     
 18     <!-- Spring Boot 启动父依赖 -->
 19     <parent>
 20         <groupId>org.springframework.boot</groupId>
 21         <artifactId>spring-boot-starter-parent</artifactId>
 22         <version>1.3.5.RELEASE</version>
 23         <relativePath />
 24     </parent>
 25     <dependencies>
 26         <dependency>
 27             <groupId>junit</groupId>
 28             <artifactId>junit</artifactId>
 29             <version>4.12</version>
 30             <scope>test</scope>
 31         </dependency>
 32         <dependency>
 33           <groupId>org.springframework</groupId>
 34           <artifactId>spring-test</artifactId>
 35           <version>4.2.6.RELEASE</version>
 36         </dependency>
 37             
 38         <!-- Spring Boot web依赖 -->
 39         <dependency>
 40             <groupId>org.springframework.boot</groupId>
 41             <artifactId>spring-boot-starter-web</artifactId>
 42         </dependency>
 43         <dependency>
 44             <groupId>org.springframework.boot</groupId>
 45             <artifactId>spring-boot-starter</artifactId>
 46         </dependency>    
 47         <!--dependency>
 48             <groupId>org.springframework.boot</groupId>
 49             <artifactId>spring-boot-starter-test</artifactId>
 50             <scope>test</scope>
 51         </dependency-->
 52         <dependency>
 53             <groupId>org.springframework.boot</groupId>
 54             <artifactId>spring-boot-starter-jdbc</artifactId>
 55         </dependency>
 56         <dependency>
 57             <groupId>org.postgresql</groupId>
 58             <artifactId>postgresql</artifactId><scope>runtime</scope>
 59         </dependency>
 60         <dependency>
 61             <groupId>org.springframework.boot</groupId>
 62             <artifactId>spring-boot-starter-actuator</artifactId>
 63         </dependency>
 64     </dependencies>
 65     <build>
 66         <pluginManagement>  
 67             <plugins>  
 68               <plugin>  
 69                 <groupId>org.eclipse.m2e</groupId>  
 70                 <artifactId>lifecycle-mapping</artifactId>  
 71                 <version>1.0.0</version>  
 72                 <configuration>  
 73                   <lifecycleMappingMetadata>  
 74                     <pluginExecutions>  
 75                       <pluginExecution>  
 76                         <pluginExecutionFilter>  
 77                           <groupId>org.apache.maven.plugins</groupId>  
 78                           <artifactId>maven-dependency-plugin</artifactId>  
 79                           <versionRange>[2.0,)</versionRange>  
 80                           <goals>  
 81                             <goal>copy-dependencies</goal>  
 82                           </goals>  
 83                         </pluginExecutionFilter>  
 84                         <action>  
 85                           <ignore />  
 86                         </action>  
 87                       </pluginExecution>  
 88                     </pluginExecutions>  
 89                   </lifecycleMappingMetadata>  
 90                 </configuration>  
 91               </plugin>  
 92             </plugins>  
 93         </pluginManagement>
 94         <plugins>
 95             <!-- 打Jar包(META-INF) -->
 96             <plugin>
 97                 <groupId>org.apache.maven.plugins</groupId>  
 98                 <artifactId>maven-jar-plugin</artifactId>  
 99                 <configuration>  
100                     <archive>  
101                         <manifest>  
102                            <addClasspath>true</addClasspath>  
103                            <classpathPrefix>lib/</classpathPrefix>  
104                            <mainClass>yg.boot.App</mainClass>  
105                         </manifest>  
106                     </archive>  
107                 </configuration>  
108             </plugin>
109             <!-- 项目资源文件 -->
110             <plugin>  
111                 <groupId>org.apache.maven.plugins</groupId>  
112                 <artifactId>maven-resources-plugin</artifactId>  
113                 <version>2.5</version>  
114                 <executions>  
115                     <execution>  
116                         <phase>compile</phase>  
117                     </execution>  
118                 </executions>  
119                 <configuration>  
120                     <encoding>${project.build.sourceEncoding}</encoding>  
121                 </configuration>  
122             </plugin>
123             <!-- 是否启动测试 -->
124             <plugin>
125                 <groupId>org.apache.maven.plugins</groupId>  
126                 <artifactId>maven-surefire-plugin</artifactId>
127                 <version>2.17</version> 
128                 <configuration>
129                   <skipTests>true</skipTests>  
130                 </configuration>
131             </plugin>
132             <!-- 复制依赖包到项目lib文件夹下 -->
133             <plugin>  
134                 <groupId>org.apache.maven.plugins</groupId>  
135                 <artifactId>maven-dependency-plugin</artifactId>  
136                 <version>2.8</version>  
137                 <executions>  
138                     <execution>  
139                         <phase>package</phase>  
140                         <goals>  
141                             <goal>copy-dependencies</goal>  
142                         </goals>  
143                     </execution>  
144                 </executions>
145                 <configuration>
146                     <outputDirectory>${project.basedir}/lib</outputDirectory>
147                     <includeScope>compile</includeScope>  
148                 </configuration>  
149             </plugin>
150             <!-- Spring boot 打包 -->
151             <plugin>
152                 <groupId>org.springframework.boot</groupId>
153                 <artifactId>spring-boot-maven-plugin</artifactId>
154             </plugin>
155         </plugins>
156     </build>
157 </project>

3.Controller

Spring
Boot框架提供的建制好工程师实现规范的RESTful接口,编写Controller代码,首先我们若以pom文件中长对应的starter,即spring-boot-starter-web,对应的xml代码示例为:
<dependency> 
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
@RestController注解是@Controller和@ResponseBody的合集,表示这是单控制器bean,并且是用函数的回来值直接填入HTTP响应体中,是REST风格的控制器。
@RequestMapping(“/test”)表示该控制器处理所有“/test”的URL请求,具体由坏函数处理,要根据HTTP的章程来区别:GET表示查询、POST表示提交、PUT表示更新、DELETE代表去。
Restful设计指南请参见:RESTFul Controller的角色,大家可看到,我此拿广大事务代码混淆在Controller的代码中。实际上,根据程序员必知之前端演进史一文所述Controller层应该举行的从是:
处理要的参数 渲染和重定向 选择Model和Service
处理Session和Cookies,我差不多认同者看法,最多又增长OAuth验证(利用拦截器实现即可)。而真的业务逻辑应该单独分处一重合来拍卖,即大的service层;

 java代码:

 1 package yg.boot.action;
 2 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 3 import org.springframework.web.bind.annotation.RequestMapping;
 4 import org.springframework.web.bind.annotation.RestController;
 5 @RestController
 6 @EnableAutoConfiguration
 7 @RequestMapping("/test")
 8 public class AppController {    
 9     @RequestMapping("/sayhello")
10     public String sayHello(){
11         return "Hello World!";
12     }
13 }

4.Spring Boot启动  

 
@SpringBootApplication是这个注解是欠应用程序入口的表明,然后出习的main函数,通过SpringApplication.run(xxxApplication.class,
args)来运作Spring Boot应用。打开SpringBootApplication注解  
可以窥见,它是由另外几独像样组合而成的:@Configuration

(等同于
spring中的xml配置文件,使用Java文件举行安排好检查类安全)、@EnableAutoConfiguration(自动配置)、@ComponentScan(组件扫描,大家老熟悉的,可以自动发现及配有Bean)

 
 pom文件里可以看来,org.postgresql这个库起作用的限定是runtime,也就是说,当应用程序启动时,如果Spring
Boot在classpath下检测到org.postgresql的存在,会活动配置postgresql数据库连接。

Application.properties代码:

 1 # DataSource settings
 2 spring.datasource.url=jdbc:postgresql://localhost:5432/jcbk
 3 spring.datasource.username=jcbk
 4 spring.datasource.password=123456
 5 spring.datasource.driver-class-name=org.postgresql.Driver
 6 
 7 # Tomcat Server settings (ServerProperties)
 8 server.port= 9080
 9 server.address= 127.0.0.1
10 server.sessionTimeout= 30
11 server.contextPath= /
12 
13 # Tomcat specifics
14 tomcat.accessLogEnabled= false
15 tomcat.protocolHeader= x-forwarded-proto
16 tomcat.remoteIpHeader= x-forwarded-for
17 tomcat.basedir=
18 tomcat.backgroundProcessorDelay=30 \# secs

java代码:

 1 package yg.boot;
 2 import org.springframework.boot.SpringApplication;
 3 import org.springframework.boot.autoconfigure.SpringBootApplication;
 4 /**
 5  * Hello world!
 6  */
 7 @SpringBootApplication
 8 public class App {    
 9     public static void main(String[] args ){
10         SpringApplication.run(App.class,args);
11     }
12 }

直运行App后,结果而下图所出示。启动后拜http://localhost:9080/test/sayhello,
输出 Hello World!,如下所示:

澳门新葡亰官网 1

5.项目打包

种打包使用maven-jar-plugin插件即可,生成boot-0.0.1-SNAPSHOT.jar。spring-boot-maven-plugin插件将boot-0.0.1-SNAPSHOT.jar重命名吧boot-0.0.1-SNAPSHOT.jar.original,然后生成新boot-0.0.1-SNAPSHOT.jar包澳门新葡亰官网,目录结构为:
+—yg
          boot
+—org
          springframework
              boot
                 loader
+—-lib
+—-META-INF
+—-application.properties

Meta-inf代码:

 1 Manifest-Version: 1.0
 2 Implementation-Vendor: Pivotal Software, Inc.
 3 Implementation-Title: Springboot
 4 Implementation-Version: 0.0.1-SNAPSHOT
 5 Implementation-Vendor-Id: ygnet
 6 Built-By: oy
 7 Build-Jdk: 1.7.0_45
 8 Class-Path: lib/spring-test-4.2.6.RELEASE.jar lib/spring-core-4.2.6.RE
 9  LEASE.jar lib/spring-boot-starter-web-1.3.5.RELEASE.jar lib/spring-bo
10  ot-starter-tomcat-1.3.5.RELEASE.jar lib/tomcat-embed-core-8.0.33.jar 
11  lib/tomcat-embed-el-8.0.33.jar lib/tomcat-embed-logging-juli-8.0.33.j
12  ar lib/tomcat-embed-websocket-8.0.33.jar lib/spring-boot-starter-vali
13  dation-1.3.5.RELEASE.jar lib/hibernate-validator-5.2.4.Final.jar lib/
14  validation-api-1.1.0.Final.jar lib/jboss-logging-3.3.0.Final.jar lib/
15  classmate-1.1.0.jar lib/jackson-databind-2.6.6.jar lib/jackson-annota
16  tions-2.6.6.jar lib/jackson-core-2.6.6.jar lib/spring-web-4.2.6.RELEA
17  SE.jar lib/spring-aop-4.2.6.RELEASE.jar lib/aopalliance-1.0.jar lib/s
18  pring-beans-4.2.6.RELEASE.jar lib/spring-context-4.2.6.RELEASE.jar li
19  b/spring-webmvc-4.2.6.RELEASE.jar lib/spring-expression-4.2.6.RELEASE
20  .jar lib/spring-boot-starter-1.3.5.RELEASE.jar lib/spring-boot-1.3.5.
21  RELEASE.jar lib/spring-boot-autoconfigure-1.3.5.RELEASE.jar lib/sprin
22  g-boot-starter-logging-1.3.5.RELEASE.jar lib/logback-classic-1.1.7.ja
23  r lib/logback-core-1.1.7.jar lib/slf4j-api-1.7.21.jar lib/jcl-over-sl
24  f4j-1.7.21.jar lib/jul-to-slf4j-1.7.21.jar lib/log4j-over-slf4j-1.7.2
25  1.jar lib/snakeyaml-1.16.jar lib/spring-boot-starter-jdbc-1.3.5.RELEA
26  SE.jar lib/tomcat-jdbc-8.0.33.jar lib/tomcat-juli-8.0.33.jar lib/spri
27  ng-jdbc-4.2.6.RELEASE.jar lib/spring-tx-4.2.6.RELEASE.jar lib/postgre
28  sql-9.4.1208.jre7.jar lib/spring-boot-starter-actuator-1.3.5.RELEASE.
29  jar lib/spring-boot-actuator-1.3.5.RELEASE.jar
30 Start-Class: yg.boot.App
31 Created-By: Apache Maven 3.0.4
32 Spring-Boot-Version: 1.3.5.RELEASE
33 Main-Class: org.springframework.boot.loader.JarLauncher
34 Archiver-Version: Plexus Archiver

 

 Start-Class为Spring boot启动类,Main-Class为main方法入口。

                                      END

 

个人档案分享用于学习C++音频处理的代码示例

与《享用用于学习C++图像处理的代码示例》为姐妹篇。

为便利学习C++音频处理并研究音频算法,

俺写了一个副初学者学习的纤维框架。

麻雀虽小五脏俱全,仅仅考虑单通道处理。

采用Decoder:dr_wav

https://github.com/mackron/dr\_libs/blob/master/dr\_wav.h

使Encoder:原本计划以dr_wav的Encode,但是dr_wav保存的文本头忘记修正音频数据的大大小小,

使用博主自己实现的代码,仅供上之用。 

dr_wav用于解析wav文件格式.

有关wav格式的解析移步至:

http://soundfile.sapp.org/doc/WaveFormat/

个人档案 1

 

个体习惯,采用int16的处理方式,也堪经过简单的改动,改也float类型。

 wav音频样本可以从维基百科上(https://en.wikipedia.org/wiki/WAV)下载。

流淌:少数wav格式不支持

 

Format Bitrate (kbit/s) 1 minute (KiB) Sample
11,025 Hz 16 bit PCM 176.4 1292 11k16bitpcm.wav
8,000 Hz 16 bit PCM 128 938 8k16bitpcm.wav
11,025 Hz 8 bit PCM 88.2 646 11k8bitpcm.wav
11,025 Hz µ-Law 88.2 646 11kulaw.wav
8,000 Hz 8 bit PCM 64 469 8k8bitpcm.wav
8,000 Hz µ-Law 64 469 8kulaw.wav
11,025 Hz 4 bit ADPCM 44.1 323 11kadpcm.wav
8,000 Hz 4 bit ADPCM 32 234 8kadpcm.wav
11,025 Hz GSM 06.10 18 132 11kgsm.wav
8,000 Hz MP3 16 kbit/s 16 117 8kmp316.wav
8,000 Hz GSM 06.10 13 103 8kgsm.wav
8,000 Hz Lernout & Hauspie SBC 12 kbit/s 12 88 8ksbc12.wav
8,000 Hz DSP Group Truespeech 9 66 8ktruespeech.wav
8,000 Hz MP3 8 kbit/s 8 60 8kmp38.wav
8,000 Hz Lernout & Hauspie CELP 4.8 35 8kcelp.wav

顺便处理耗时划算,示例演示了一个简便的以音频前面一半静音处理,并略注释了一下片段逻辑。

总体代码:

#include <stdio.h>
#include <stdlib.h>    
#include <stdint.h>    
#include <time.h> 
#include <iostream> 
//采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"

auto const epoch = clock();
static double now()
{
    return  (clock() - epoch);
};

template <typename FN>
static double bench(const FN &fn)
{
    auto took = -now();
    return (fn(), took + now()) / 1000;
}

//写wav文件
void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_t totalSampleCount) {

    FILE* fp = fopen(filename, "wb");
    if (fp == NULL) {
        printf("文件打开失败.\n");
        return;
    }
    //修正写入的buffer长度
    totalSampleCount *= sizeof(int16_t);
    int nbit = 16;
    int FORMAT_PCM = 1;
    int nbyte = nbit / 8;
    char text[4] = { 'R', 'I', 'F', 'F' };
    uint32_t long_number = 36 + totalSampleCount;
    fwrite(text, 1, 4, fp);
    fwrite(&long_number, 4, 1, fp);
    text[0] = 'W';
    text[1] = 'A';
    text[2] = 'V';
    text[3] = 'E';
    fwrite(text, 1, 4, fp);
    text[0] = 'f';
    text[1] = 'm';
    text[2] = 't';
    text[3] = ' ';
    fwrite(text, 1, 4, fp);

    long_number = 16;
    fwrite(&long_number, 4, 1, fp);
    int16_t short_number = FORMAT_PCM;//默认音频格式
    fwrite(&short_number, 2, 1, fp);
    short_number = 1; // 音频通道数
    fwrite(&short_number, 2, 1, fp);
    long_number = sampleRate; // 采样率
    fwrite(&long_number, 4, 1, fp);
    long_number = sampleRate * nbyte; // 比特率
    fwrite(&long_number, 4, 1, fp);
    short_number = nbyte; // 块对齐
    fwrite(&short_number, 2, 1, fp);
    short_number = nbit; // 采样精度
    fwrite(&short_number, 2, 1, fp);
    char data[4] = { 'd', 'a', 't', 'a' };
    fwrite(data, 1, 4, fp);
    long_number = totalSampleCount;
    fwrite(&long_number, 4, 1, fp);
    fwrite(buffer, totalSampleCount, 1, fp);
    fclose(fp);
}
//读取wav文件
int16_t* wavRead_int16(char* filename, uint32_t* sampleRate, uint64_t    *totalSampleCount) {

    unsigned int channels;
    int16_t* buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
    if (buffer == NULL) {
        printf("读取wav文件失败.");
    }
    //仅仅处理单通道音频
    if (channels != 1)
    {
        drwav_free(buffer);
        buffer = NULL;
        *sampleRate = 0;
        *totalSampleCount = 0;
    }
    return buffer;
}

//分割路径函数
void splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
{
    const char* end;
    const char* p;
    const char* s;
    if (path[0] && path[1] == ':') {
        if (drv) {
            *drv++ = *path++;
            *drv++ = *path++;
            *drv = '\0';
        }
    }
    else if (drv)
        *drv = '\0';
    for (end = path; *end && *end != ':';)
        end++;
    for (p = end; p > path && *--p != '\\' && *p != '/';)
        if (*p == '.') {
            end = p;
            break;
        }
    if (ext)
        for (s = end; (*ext = *s++);)
            ext++;
    for (p = end; p > path;)
        if (*--p == '\\' || *p == '/') {
            p++;
            break;
        }
    if (name) {
        for (s = p; s < end;)
            *name++ = *s++;
        *name = '\0';
    }
    if (dir) {
        for (s = path; s < p;)
            *dir++ = *s++;
        *dir = '\0';
    }
}

int main(int argc, char* argv[])
{
    std::cout << "Audio Processing " << std::endl;
    std::cout << "博客:http://tntmonks.cnblogs.com/" << std::endl;
    std::cout << "支持解析单通道wav格式." << std::endl;

    if (argc < 2) return -1;
    char* in_file = argv[1];

    //音频采样率
    uint32_t sampleRate = 0;
    //总音频采样数
    uint64_t totalSampleCount = 0;
    int16_t* wavBuffer = NULL;
    double nLoadTime = bench([&]
    {
        wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);
    });
    std::cout << " 加载耗时: " << int(nLoadTime * 1000) << " 毫秒" << std::endl;

    //如果加载成功
    if (wavBuffer != NULL)
    {
        //将前面一般进行静音处理,直接置零即可
        for (uint64_t i = 0; i < totalSampleCount / 2; i++)
        {
            wavBuffer[i] = 0;
        }
    }
    //保存结果
    double nSaveTime = bench([&]
    {
        char drive[3];
        char dir[256];
        char fname[256];
        char ext[256];
        char out_file[1024];
        splitpath(in_file, drive, dir, fname, ext);
        sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);
        wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount);
    });
    std::cout << " 保存耗时: " << int(nSaveTime * 1000) << " 毫秒" << std::endl;
    if (wavBuffer)
    {
        free(wavBuffer);
    }
    getchar();
    std::cout << "按任意键退出程序 \n" << std::endl;
    return 0;
}

 

以身作则具体流程也:

加载wav(拖放wav文件及可执行文件上)->简单静音处理->保存wav

并针对性 加载,保存 这2单环节还进行了耗时划算并出口。

  

假使发生另外相关问题要么要求也得邮件联系我探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

 

若此博文能帮到你,欢迎扫码小额赞助。

微信:  

 个人档案 2

 

支付宝: 

个人档案 3

个人档案Java入门(二):注释和核心数据列

上次经过eclipse在支配高出口了hello
world,是休是出接触小震动啊,今天随着介绍Java基础知识。

一、Java注释

1、Java注释语句不见面吃编译器运行,不用顾虑代码因为众多注语句显得臃肿而影响程序运行速度。

2、Java注释有三栽写法。

相同凡夹斜杠 //
。需要注掉哪一行就补给加至啊一行前面,在加上汉语注释时,在对斜杠//后面添加一个空格,在写注释内容,这是编码规范。

二是 /* */ 。这样的注释标记可以注释多行,就无须每行都用单行注释。

三是 /** */ 。这样的注释也足以注释多执行,多在类名、方法名前。

package javalearningday01;

/**
 * Java注释的使用
 * @author Administrator
 * @date 2018年1月14日
 */
public class UseCommentsTag {

    public static void main(String[] args) {
        /*
         * 注释方法二
         * 可以注释多行
         */
        System.out.println("这是主方法");
    }

    /**
     * 注释方法三
     * @return String 返回String
     */
    public String useTag(){
        // 注释方法二,单行注释
        return "这是普通方法";
    }

    /**
     * 这里可以介绍这个方法是干什么的
     * @param str 参数名,说明传递进来的参数是什么
     * @return 返回值,说明返回什么样的数据
     */
    public String useMethod(String str){
        return "Hello"+str;
    }
}

 

其次、Java基本数据列

以知情基本数据列之前,先聊聊存储单元。电脑是休见面认识你输入的华语、汉字等情节,而是以其变为机会读懂的老二进制编码,就是由0和1做的数字长串,因此呢起矣不同之进制数,我们常常因此之凡十进制数(如2,3,100抵),但是还发二进制、八进制、十六进制。

位(bit):1只各类表示用于存储1或0底空中,是极度小数码单位。

字节(byte):比较常用之数单位,1 byte = 8 bit。

千字节(K):1 k = 1024 byte。

兆字节(M):1 M = 1024 K。

G字节:1 G = 1024 M。

T字节:1 T = 1024 G。

Java有4种多少列,一凡整型,二是浮点型,三是字符型,四凡是布尔型。

个人档案 1

下直接上中心数据类的系操作。

package javalearningday01;

/**
 * Java基本数据类型
 * @author 小川94
 * @date 2018年1月14日
 */
public class DataType {

    public static void main(String[] args) {
        DataType dt = new DataType();
        dt.viewChar();
        dt.viewByte();
        dt.viewShort();
        dt.viewLong();
        dt.viewFloat();
        dt.viewDouble();
        dt.viewBoolean();
    }

    /**
     * 字符型:char,占两个字节,16位
     */
    public void viewChar(){
        System.out.println("=========== 查看char方法开始 =============");
        // Character是char的包装类
        char charMaxValue = Character.MAX_VALUE;
        System.out.println((int)charMaxValue); // 65535
        char charMinValue = Character.MIN_VALUE;
        System.out.println((int)charMinValue); // 0
        // char和int之间的转换
        char charNumber = 'A';
        System.out.println((int)charNumber); // 65
        char charNumber2 = 65;
        System.out.println(charNumber2); // A
        // 查看 中 对应Unicode编码值
        char charNumber3 = '中';
        System.out.println((int)charNumber3); // 20013
        System.out.println("=========== 查看char方法结束 =============");
    }

    /**
     * 整型:byte,占1个字节,8位
     * 1 byte (1个字节) = 8 bit (8个位,8个二进制编码)
     * 八位二进制                  1   1  1  1  1  1  1  1
     * 八位二进制对应整数 128 64 32 16  8  4  2  1
     * 为0 二进制则是0000 0000
     * 八位二进制表示:1     +    1     =   2  
     *         00000001 + 00000001 = 00000002 = 00000010  这就是逢二进一
     */
    public void viewByte(){
        System.out.println("=========== 查看byte方法开始 =============");
        // Byte是byte的包装类
        byte byteMaxValue = Byte.MAX_VALUE;
        System.out.println(byteMaxValue); // byteMaxValue = 127
        byte byteMinValue = Byte.MIN_VALUE;
        System.out.println(byteMinValue); // byteMinValue = -128
        System.out.println(Integer.toBinaryString(byteMinValue));
        // 将3转为8位二进制,0000 0011,
        System.out.println(Integer.toBinaryString(3)); //11
        System.out.println("=========== 查看byte方法结束 =============");
    }

    /**
     * 整型:short,占2个字节,16位
     */
    public void viewShort(){
        System.out.println("=========== 查看short方法开始 =============");
        // Short是short的包装类
        short shortMaxValue = Short.MAX_VALUE; 
        System.out.println(shortMaxValue); // 32767
        short shortMinValue = Short.MIN_VALUE;
        System.out.println(shortMinValue); // -32768
        short shortNumber = 323+4343;
        System.out.println(shortNumber); // 4666
        System.out.println("=========== 查看short方法结束 =============");
    }

    /**
     * 整型:int,4字节,32位
     */
    public void viewInt(){
        System.out.println("=========== 查看int方法开始 =============");
        // 查看int的最大、最小值,Integer是int的包装类
        int maxIntNumber = Integer.MAX_VALUE;
        System.out.println(maxIntNumber); // maxIntNumber = 2147483647
        int minIntNumber = Integer.MIN_VALUE;
        System.out.println(minIntNumber); // minIntNumber = -2147483648
        // 值溢出,计算时合理估算值大小,取合适范围的数据类型
        int overFlow = 1299999999+1299999999;
        System.out.println(overFlow); // overFlow = -1694967298
        // 将int换成long类型
        long suitRange = 1299999999L+1299999999L;
        System.out.println(suitRange); // suitRange = 2599999998
        // 1299999999字面量还是int,1299999999+1299999999算出来的值还是int类型
        long suitRange2 = 1299999999+1299999999;
        System.out.println(suitRange2); // suitRange2 = -1694967298
        // 1299999999L的字面量是long,1299999999的字面量是int,两者相加,取占位大的一方为结果值的字面量
        long suitRange3 = 1299999999L+1299999999;
        System.out.println(suitRange3); // suitRange3 = 2599999998
        // 字符串和int之间的转换,只能用于纯数字、合适范围值之间的转换
        String intStr = "1278098";
        int intNumber = Integer.parseInt(intStr);
        System.out.println(intNumber); // intNumber = 1278098
        System.out.println("=========== 查看int方法结束 =============");
    }

    /**
     * 整型:long,占8个字节,64位
     * 在赋值时,需要在数值尾部加一个l(小写L)或者L
     */
    public void viewLong(){
        System.out.println("=========== 查看long方法开始 =============");
        // Long是long类型的包装类
        long longMaxValue = Long.MAX_VALUE;
        System.out.println(longMaxValue); // 9223372036854775807
        long longMinValue = Long.MIN_VALUE;
        System.out.println(longMinValue); // -9223372036854775808
        long longNumber = 3999+7328328323728332L;
        System.out.println(longNumber); // 7328328323732331
        System.out.println("=========== 查看long方法结束 =============");
    }

    /**
     * 浮点型:float,占4个字节,也称为单精度类型,32位
     * 在赋值时,需要在数值尾部加一个f或者F
     */
    public void viewFloat(){
        System.out.println("=========== 查看float方法开始 =============");
        // float的最大值、最小值,Float是float的包装类
        float floatMaxValue = Float.MAX_VALUE; 
        System.out.println(floatMaxValue); // floatMaxValue = 3.4028235E38 
        float foatMinValue = Float.MIN_VALUE;
        System.out.println(foatMinValue); // foatMinValue = 1.4E-45
        float floatNumber = 3.14f+3;
        System.out.println(floatNumber);
        System.out.println("=========== 查看float方法结束 =============");
    }

    /**
     * 浮点型:double,占8个字节,也称为双精度类型,64位
     * 在赋值时,需要在数值尾部加一个d或者D
     */
    public void viewDouble(){
        System.out.println("=========== 查看double方法开始 =============");
        // double的最大值、最小值,Double是double的包装类
        double doubleMaxValue = Double.MAX_VALUE;
        System.out.println(doubleMaxValue); // doubleMaxValue = 1.7976931348623157E308
        double doubleMinValue = Double.MIN_VALUE;
        System.out.println(doubleMinValue); // doubleMinValue = 4.9E-324
        double doubleNum = 3.1d+3.2D;
        System.out.println(doubleNum); // doubleNum = 6.300000000000001
        System.out.println("=========== 查看double方法结束 =============");
    }

    /**
     * 布尔型:boolean,只有true、false两个值,用于逻辑判断
     */
    public void viewBoolean(){
        System.out.println("=========== 查看boolean方法开始 =============");
        boolean boo = true;
        boolean boo2 = false;
        // Boolean是boolean的包装类
        boolean boo3 = Boolean.TRUE;
        boolean boo4 = Boolean.FALSE;
        System.out.println(boo == boo3); // true
        System.out.println(boo2 == boo4); // true
        boolean boo5 = 2 > 3; 
        System.out.println(boo5); // boo3 = false
        System.out.println("=========== 查看boolean方法结束 =============");
    }

}

 

Java入门(一)和Java入门(二)的源码已经达成传Git,地址:https://github.com/XiaoChuan94/javalearning,可以参考。

 

章首发于自己之个人公众号:悦乐书。喜欢享受共同及放了之歌,看罢之影片,读了的书,敲过之代码,深夜的想。期待您的关怀!

个人档案 2

大众号后台输入关键字“Java学习电子书”,即可获得12本Java学习相关的电子书资源,如果经济能力允许,还求支持图书作者的纸质正版图书,创作是。

mp3格式转wav格式 附完整C++算法实现代码

近年偶尔间看一个开源项目minimp3

Minimalistic MP3 decoder single header library

种地址:

https://github.com/lieff/minimp3

单文件头的最小mp3解码器。

一直十分怀念减掉时间可以看上一看押。

极致好的学习方法就是是描写个实用性的工程项目。

比如说落实mp3转wav格式。

嗯,这篇博文就是这样来的。

翻阅了下minimp3的源码,有一两处在小bug,

以此解码算法可以更进一步提速优化的地方还发无数。

末尾来时空,再美庖丁解牛。

根据这个库房,实现mp3转wav的代码行数不交300实施。

细而简单,算是简单的抛砖引玉了。

私家习惯,很少写注释,

为此尽可能将代码写得清晰易懂,当然为闹犯懒的时候。

 完整代码:

#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE 1 
#define _CRT_NONSTDC_NO_DEPRECATE 1
#include <stdio.h>
#include <stdlib.h>    
#include <stdint.h>    
#include <time.h> 
#include <iostream>  

// ref:https://github.com/lieff/minimp3/blob/master/minimp3.h
#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"
#include <sys/stat.h>
auto const epoch = clock();
static double now()
{
    return  (clock() - epoch);
};

template <typename FN>
static double bench(const FN &fn)
{
    auto took = -now();
    return (fn(), took + now()) / 1000;
}

//写wav文件
void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_t totalSampleCount, int channels = 1) {

    FILE* fp = fopen(filename, "wb");
    if (fp == NULL) {
        printf("文件打开失败.\n");
        return;
    }
    //修正写入的buffer长度
    totalSampleCount *= sizeof(int16_t)*channels;
    int nbit = 16;
    int FORMAT_PCM = 1;
    int nbyte = nbit / 8;
    char text[4] = { 'R', 'I', 'F', 'F' };
    uint32_t long_number = 36 + totalSampleCount;
    fwrite(text, 1, 4, fp);
    fwrite(&long_number, 4, 1, fp);
    text[0] = 'W';
    text[1] = 'A';
    text[2] = 'V';
    text[3] = 'E';
    fwrite(text, 1, 4, fp);
    text[0] = 'f';
    text[1] = 'm';
    text[2] = 't';
    text[3] = ' ';
    fwrite(text, 1, 4, fp);

    long_number = 16;
    fwrite(&long_number, 4, 1, fp);
    int16_t short_number = FORMAT_PCM;//默认音频格式
    fwrite(&short_number, 2, 1, fp);
    short_number = channels; // 音频通道数
    fwrite(&short_number, 2, 1, fp);
    long_number = sampleRate; // 采样率
    fwrite(&long_number, 4, 1, fp);
    long_number = sampleRate * nbyte; // 比特率
    fwrite(&long_number, 4, 1, fp);
    short_number = nbyte; // 块对齐
    fwrite(&short_number, 2, 1, fp);
    short_number = nbit; // 采样精度
    fwrite(&short_number, 2, 1, fp);
    char data[4] = { 'd', 'a', 't', 'a' };
    fwrite(data, 1, 4, fp);
    long_number = totalSampleCount;
    fwrite(&long_number, 4, 1, fp);
    fwrite(buffer, totalSampleCount, 1, fp);
    fclose(fp);
}
//读取文件buffer
char *getFileBuffer(const char *fname, int *size)
{
    FILE * fd = fopen(fname, "rb");
    if (fd == 0)
        return 0;
    struct stat st;
    char *file_buf = 0;
    if (fstat(fileno(fd), &st) < 0)
        goto doexit;
    file_buf = (char *)malloc(st.st_size + 1);
    if (file_buf != NULL)
    {
        if (fread(file_buf, st.st_size, 1, fd) < 1)
        {
            fclose(fd);
            return 0;
        }
        file_buf[st.st_size] = 0;
    }

    if (size)
        *size = st.st_size;
doexit:
    fclose(fd);
    return file_buf;
}
//mp3解码
int16_t* DecodeMp3ToBuffer(char* filename, uint32_t *sampleRate, uint32_t *totalSampleCount, unsigned int *channels)
{
    int music_size = 0;
    int alloc_samples = 1024 * 1024, num_samples = 0;
    int16_t *music_buf = (int16_t *)malloc(alloc_samples * 2 * 2);
    unsigned char *file_buf = (unsigned char *)getFileBuffer(filename, &music_size);
    if (file_buf != NULL)
    {
        unsigned char *buf = file_buf;
        mp3dec_frame_info_t info;
        mp3dec_t dec;

        mp3dec_init(&dec);
        for (;;)
        {
            int16_t frame_buf[2 * 1152];
            int samples = mp3dec_decode_frame(&dec, buf, music_size, frame_buf, &info);
            if (alloc_samples < (num_samples + samples))
            {
                alloc_samples *= 2;
                int16_t* tmp = (int16_t *)realloc(music_buf, alloc_samples * 2 * info.channels);
                if (tmp)
                    music_buf = tmp;
            }
            if (music_buf)
                memcpy(music_buf + num_samples*info.channels, frame_buf, samples*info.channels * 2);
            num_samples += samples;
            if (info.frame_bytes <= 0 || music_size <= (info.frame_bytes + 4))
                break;
            buf += info.frame_bytes;
            music_size -= info.frame_bytes;
        }
        if (alloc_samples > num_samples)
        {
            int16_t* tmp = (int16_t *)realloc(music_buf, num_samples * 2 * info.channels);
            if (tmp)
                music_buf = tmp;
        }

        if (sampleRate)
            *sampleRate = info.hz;
        if (channels)
            *channels = info.channels;
        if (num_samples)
            *totalSampleCount = num_samples;

        free(file_buf);
        return music_buf;
    }
    if (music_buf)
        free(music_buf);
    return 0;
}
//分割路径函数
void splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
{
    const char* end;
    const char* p;
    const char* s;
    if (path[0] && path[1] == ':') {
        if (drv) {
            *drv++ = *path++;
            *drv++ = *path++;
            *drv = '\0';
        }
    }
    else if (drv)
        *drv = '\0';
    for (end = path; *end && *end != ':';)
        end++;
    for (p = end; p > path && *--p != '\\' && *p != '/';)
        if (*p == '.') {
            end = p;
            break;
        }
    if (ext)
        for (s = end; (*ext = *s++);)
            ext++;
    for (p = end; p > path;)
        if (*--p == '\\' || *p == '/') {
            p++;
            break;
        }
    if (name) {
        for (s = p; s < end;)
            *name++ = *s++;
        *name = '\0';
    }
    if (dir) {
        for (s = path; s < p;)
            *dir++ = *s++;
        *dir = '\0';
    }
}


int main(int argc, char* argv[])
{
    std::cout << "Audio Processing " << std::endl;
    std::cout << "博客:http://tntmonks.cnblogs.com/" << std::endl;
    std::cout << "mp3 转 wav." << std::endl;

    if (argc < 2) return -1;
    char* in_file = argv[1];

    //总音频采样数
    uint32_t totalSampleCount = 0;
    //音频采样率
    uint32_t sampleRate = 0;
    //通道数
    unsigned int channels = 0;
    int16_t* wavBuffer = NULL;
    double nLoadTime = bench([&]
    {
        wavBuffer = DecodeMp3ToBuffer(in_file, &sampleRate, &totalSampleCount, &channels);
    });
    std::cout << " 加载耗时: " << int(nLoadTime * 1000) << " 毫秒" << std::endl;

    //保存结果
    double nSaveTime = bench([&]
    {
        char drive[3];
        char dir[256];
        char fname[256];
        char ext[256];
        char out_file[1024];
        splitpath(in_file, drive, dir, fname, ext);
        sprintf(out_file, "%s%s%s.wav", drive, dir, fname);
        wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount, channels);
    });
    std::cout << " 保存耗时: " << int(nSaveTime * 1000) << " 毫秒" << std::endl;
    if (wavBuffer)
    {
        free(wavBuffer);
    }
    getchar();
    std::cout << "按任意键退出程序 \n" << std::endl;
    return 0;
}

 

示范具体流程也:

加载mp3(拖放mp3文件及可执行文件上)->解码mp3->保存wav

连针对性 加载,保存 这2个环节还进展了耗时算并出口。

  

一旦发生其他相关题材或者要求也得以邮件联系个人探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

 

若此博文能协助到您,欢迎扫码小额赞助。

微信:  

 图片 1

 

支付宝: 

图片 2

网站地图xml地图