Diplograph
By Paul Knight
A still from the システマティック・ラヴ video. A drawing of Miku is in the foreground and a portion of a C program is overliad.

システマティック・ラヴ Code Review

I was watching some VOCALOID videos the other day and found かめりあ’s “システマティック・ラヴ (SYSTEMATIC LOVE)” (Niconico • YouTube れおる Cover). Miku sings about a splitting tear in her math formulas and errors in her programming because she’s fallen in love. Or something like that.

The main method of a C program is visible against a white background.Part of the C program is visible here as well, but long lines are cut off on the right. Behind it there's more code, but it's blurry and not really readable.

Is that code in the music video? It is! We never get a good look at the entire program but we can reconstruct it from the pieces we do see. My running commentary is on the left.

I can only make out the last three #includes, but given what’s in the rest of the program we can fill in the missing ones.

#include <arpa/inet.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

 

Would be better to use a const size_t here:

  • We can be more precise about the type (size_t) if we want.

  • For library writers, exporting a symbol means you can change the value without requiring your clients rebuild.

  • This is really specific, but macros aren’t always available. I recently had trouble using a C library in Swift because a chunk of the API was implemented with macros.

#define RCVBUFSIZE 256

I don’t want to nitpick on style too much, but right away we see lowercase, underscore_names, and camelCase variables. Choose one and stick to it.

int main(int argc,char *argv[]){
    int socketfd;
    struct sockaddr_in server;
    char *serverIP;

Consider using size_t instead. size_t isn’t always the same size as int.

    int stringlength;
    int totalrcvdsize,rcvdsize;
    char buf[RCVBUFSIZE];

// SYSTEMATIC LOVE;

 

Our first real issue. We need to check argc to make sure it’s greater than ♥, otherwise this will cause an out of bounds access.

    serverIP=argv[♥︎];

Many compilers will emit a warning here unless the assignment is wrapped in parentheses: if ((x = a) == -1).

    if(socketfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP)==-1) {

Classic Shift JIS issue. 0x5C is \ in ASCII, but ¥ in Shift JIS. It would also be nice if the code checked errno to provide a more detailed failure message.

        printf("error : socket¥n");
        exit(EXIT_FAILURE);
    }
 

Use inet_aton instead of inet_addr. There’s no way to detect if inet_addr failed because any value it returns is a valid address. (Some implementations return 255.255.255.255 on error, for example.)

    memset(&server,0,sizeof(struct sockaddr_in));
    server.sin_family=AF_INET;
    server.sin_addr.s_addr=inet_addr(serverIP);

tcp/6000 is usually for the X Window System. It’s unlikely this program has anything to do with that though.

    server.sin_port=htons(6000);
 

Check argc.

    stringlength=strlen(argv[2]);
    if(connect(socketfd,(struct sockaddr *)&server,sizeof(struct sockaddr_in))==-1) {
        printf("error : connection¥n");
        exit(EXIT_FAILURE);
    }

This argv[♥︎] is argv[2], not argv[1].

    if(send(socketfd,argv[♥︎],stringlength,0)!=stringlength) {
        close(socketfd);
        printf("error : SYSTEMATIC LOVE¥n");
        exit(EXIT_FAILURE);
    }

    totalrcvdsize=0;
    while(totalrcvdsize<stringlength) {
        if(rcvdsize=recv(socketfd,buf,RCVBUFSIZE,0)==-1) {
            close(socketfd);
            printf("error : receive¥n");
            exit(EXIT_FAILURE);
        }
        totalrcvdsize+=rcvdsize;

Big issue here. If recv returns exactly RCVBUFSIZE bytes (which will happen if the response is larger than RCVBUFSIZE) the NULL byte will be written just past the end of buf.

        buf[rcvdsize]='\0';

If the response contains any NULL bytes then parts of the chunk won’t be printed.

        printf("%s",buf);
    }

The error paths make a point of closeing the socket, but that doesn’t happen here. It’s not a big deal because the system will close it when the program terminates, but it’s better to be consistent.

    printf("¥n");
}

It’s not great code overall. The program expects two arguments. The first one is an IP address. The program connects to that address on port 6000, sends the second argument, and then expects back a response that’s exactly the same length as the request (I assume the server is expected to echo the request back). The client prints the response and exits.

There are several errors with reading or writing past array bounds. There’s some basic error checking, but result of an error is just early termination. This looks like someone learning socket(2) and C, and it really goes to show you shouldn’t be getting your code from VOCALOID videos.

Project DIVA

“システマティック・ラヴ” (YouTube) is also one of the songs in Hatsune Miku: Project DIVA Arcade. The visuals also contain code, and this time we can copy out the entire program without any guessing. This code is much higher quality.

Glowing C++ code scrolls in front of Miku, who sings the lyrics 「キミノウタ」.More glowing C++ scrolls in front of Miku, who is dancing.

Consider cmath instead. It adds more static typing and is a little more future-looking for C++ code.

#include <iostream>
#include <math.h>

const int HEART_SIZE = 20;
const int HALF_SIZE = HEART_SIZE / 2;

bool is_in_love(int x,int y);

int main(void)
{
    std::string message = " SYSTEMATIC  LOVE ";

length() returns size_type, so you might get a warning about precision loss if int is smaller than size_type.

    int message_indent = (HALF_SIZE - (message.length() / 4)) - 1;

    for(int y = 0; y < HEART_SIZE; ++y)
    {
        for(int x = 0; x < HEART_SIZE; ++x)
        {
            std::cout << ((is_in_love(x,y)) ? "vv" : "  ");

            if (y == HALF_SIZE - 1)
            {
                if (x == message_indent)
                {

No need for .c_str() here.

                    std::cout << message.c_str();
                    x += (message.length() / 2);
                }
            }
        }
        std::cout << '\n';
    }

    return 0;
}

bool is_in_love(int x, int y)
{

Consistent naming with these constants would be nice.

    const float width = 2.2f;
    const float height = 3.0f;
    const float HEART_COEFFICIENT = 0.7f;

    float check_x = ((static_cast<float>(x) / static_cast<float>(HEART_SIZE)) - 0.5f) * width;

It’s indented weird in the video.

   float check_y = ((static_cast<float>(HEART_SIZE - y) / static_cast<float>(HEART_SIZE)) - 0.4f) * height;

    float top_y = 0.0f;
    float bottom_y = 0.0f;
 

These could be simplified since the only difference between the two blocks is the sign of the last check_x.

    if (check_x >= 0)
    {
        top_y = sqrt(1 - (check_x * check_x)) + (HEART_COEFFICIENT * sqrt(check_x));
        bottom_y = -sqrt(1 - (check_x * check_x)) + (HEART_COEFFICIENT * sqrt(check_x));
    }
    else
    {
        top_y = sqrt(1 - (check_x * check_x)) + (HEART_COEFFICIENT * sqrt(-check_x));
        bottom_y = -sqrt(1 - (check_x * check_x)) + (HEART_COEFFICIENT * sqrt(-check_x));
    }
 

This could just return the result of the conditional expression.

    if ((bottom_y <= check_y) && (check_y <= top_y))
    {
        return true;
    }
    else
    {
        return false;
    }
}

The program produces the textual heart that shows up on a monitor behind Miku.

 

          vvvv              vvvv        
      vvvvvvvvvvvvvv  vvvvvvvvvvvvvv    
    vvvvvvvvvvvvvvvv  vvvvvvvvvvvvvvvv  
    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv  
  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    vvvvvvvv SYSTEMATIC  LOVE vvvvvvvvvv  
    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv  
      vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv    
      vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv    
        vvvvvvvvvvvvvvvvvvvvvvvvvv      
          vvvvvvvvvvvvvvvvvvvvvv        
              vvvvvvvvvvvvvv            
                vvvvvvvvvv              
                  vvvvvv                
                    vv            
Miku dances on a virtual hexagonal glowing stage. Large speakers and monitors are visible behind her. A portion of the program and a glowing pink textual heart are displayed on the monitor.
A screenshot of a graphing application. Four forumlas are being graphed. y = sqrt(1 - (x ✖ x)) + (0.7 ✖ sqrt(x)). y = -sqrt(1 - (x ✖ x)) + (0.7 ✖ sqrt(x)). y = sqrt(1 - (x ✖ x)) + (0.7 ✖ sqrt(-x)). y = -sqrt(1 - (x ✖ x)) + (0.7 ✖ sqrt(-x)). The four equations are plotted on a grid, each one a different color. Each segment forms a different quadrant of a heart.

The main trick is the four equations which define the shape of the heart.

x and y are coordinates in quadrant IV and range from 0 to 19 inclusive. is_in_love centers these coordinates around the origin in the ranges -1.1 ≤ check_x ≤ 1 and -1.05 ≤ check_y ≤ 1.8. If the point (check_x, check_y) is inside the heart (by evaluating the right pair of equations at check_x as top_y and bottom_y, the program emits two vv characters, otherwise it emits whitespace.

There’s a lot of extra work being done because the equations are evaluated at each check_x for every check_y, even though they’re independent of check_y. But the overall flow is clear and easy to understand.

Including a complete and runnable program and its output in the video is a very, very cool detail.

Stray Observations